{"id":26851,"date":"2026-07-17T06:42:19","date_gmt":"2026-07-17T06:42:19","guid":{"rendered":"https:\/\/umang.pk\/2026\/07\/17\/nestjs%d8%8c-grpc%d8%8c-%d8%a7%d9%88%d8%b1-docker-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88\/"},"modified":"2026-07-17T06:42:19","modified_gmt":"2026-07-17T06:42:19","slug":"nestjs%d8%8c-grpc%d8%8c-%d8%a7%d9%88%d8%b1-docker-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88","status":"publish","type":"post","link":"https:\/\/umang.pk\/ur\/2026\/07\/17\/nestjs%d8%8c-grpc%d8%8c-%d8%a7%d9%88%d8%b1-docker-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88\/","title":{"rendered":"NestJS\u060c gRPC\u060c \u0627\u0648\u0631 Docker \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u0645\u06cc\u06ba \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0646\u0627\u0641\u0630 \u06a9\u06cc\u0627 \u062c\u0627\u0626\u06d2"},"content":{"rendered":"\n<div id=\"\">\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u0622\u067e NestJS \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u067e\u06d2 \u067e\u0627\u0644 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4 \u0631\u0627\u0633\u062a\u06d2 \u0645\u06cc\u06ba\u060c \u0622\u067e \u0633\u06cc\u06a9\u06be\u06cc\u06ba \u06af\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0645\u0646\u0637\u0642 \u06a9\u0648 \u0627\u0633 \u06a9\u06cc \u0627\u067e\u0646\u06cc \u0633\u0631\u0648\u0633 \u0645\u06cc\u06ba \u0627\u0644\u06af \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u060c gRPC \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u0646\u0627\u060c RabbitMQ \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u0634\u0627\u0626\u0639 \u06a9\u0631\u0646\u0627\u060c \u0627\u0648\u0631 Docker \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u0648 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u0646\u0627\u06d4<\/p>\n<p>\u0628\u0627\u0644\u0622\u062e\u0631\u060c \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0627\u06cc\u06a9 \u0642\u0627\u0628\u0644 \u062a\u0648\u0633\u06cc\u0639 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc\u0648\u06ba \u06a9\u0627 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u06c1\u0648\u06af\u0627 \u062c\u0633\u06d2 \u0645\u062a\u0639\u062f\u062f \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0688\u0648\u0645\u06cc\u0646\u0632 \u0645\u06cc\u06ba \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-table-of-contents\">\u0627\u0646\u0688\u06cc\u06a9\u0633<\/h2>\n<h2 id=\"heading-introduction\">\u062a\u0639\u0627\u0631\u0641<\/h2>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0645\u0646\u0637\u0642 \u06c1\u0631 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633 \u0633\u06d2 \u062a\u0639\u0644\u0642 \u0646\u06c1\u06cc\u06ba \u0631\u06a9\u06be\u062a\u06cc\u06d4 \u067e\u06d2 \u067e\u0627\u0644 API \u06a9\u0627\u0644\u0632 \u06a9\u0648 \u0645\u062a\u0639\u062f\u062f \u0645\u0642\u0627\u0645\u0627\u062a \u067e\u0631 \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0631\u0646\u0627 <code>user-service<\/code>, <code>order-service<\/code>\u0627\u0648\u0631 <code>billing-service<\/code>\u0646\u062a\u0627\u0626\u062c \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06cc\u06ba:<\/p>\n<ul>\n<li>\n<p>\u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u067e\u06d2 \u067e\u0627\u0644 \u0627\u0633\u0646\u0627\u062f \u0627\u0648\u0631 SDK \u06a9\u0648\u0688<\/p>\n<\/li>\n<li>\n<p>\u0645\u062a\u0636\u0627\u062f \u062e\u0631\u0627\u0628\u06cc \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u0646\u0627 \u0627\u0648\u0631 \u0642\u0627\u0628\u0644\u06cc\u062a<\/p>\n<\/li>\n<li>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u062c\u0646 \u06a9\u0627 \u0622\u0688\u0679 \u06a9\u0631\u0646\u0627 \u0645\u0634\u06a9\u0644 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u062a\u06a9\u0644\u06cc\u0641 \u062f\u06c1 \u0645\u0627\u062d\u0648\u0644 \u06a9\u06cc \u0645\u0646\u062a\u0642\u0644\u06cc (\u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u0633\u06d2 \u0632\u0646\u062f\u06c1 \u062a\u06a9)<\/p>\n<\/li>\n<\/ul>\n<p>\u062d\u0644 \u0627\u06cc\u06a9 \u0648\u0642\u0641 \u0634\u062f\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc\u0648\u06ba \u06a9\u06cc \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633 \u06c1\u06d2 \u062c\u0648 \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06d2 \u062a\u0645\u0627\u0645 \u062a\u0639\u0627\u0645\u0644\u0627\u062a \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4 \u062f\u0648\u0633\u0631\u06cc \u0633\u0631\u0648\u0633\u0632 \u0627\u0633\u06d2 gRPC \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u06a9\u0627\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c RabbitMQ \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0646\u0634\u0631 \u06a9\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u0633 \u0633\u06d2 \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u06a9\u0648 \u0627\u067e\u0646\u0627 \u0688\u06cc\u0679\u0627 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0645\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u06af\u0627\u0626\u06cc\u0688 \u0622\u067e \u06a9\u0648 \u0627\u0635\u0644 \u0627\u0633\u0679\u06cc\u06a9 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0644\u06d2 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0641\u0631\u0634<\/th>\n<th>\u0679\u06cc\u06a9\u0646\u0627\u0644\u0648\u062c\u06cc<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a<\/td>\n<td>NestJS<\/td>\n<\/tr>\n<tr>\n<td>\u0627\u0646\u0679\u0631 \u0633\u0631\u0648\u0633 \u0645\u0648\u0627\u0635\u0644\u0627\u062a<\/td>\n<td>\u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc<\/td>\n<\/tr>\n<tr>\n<td>\u0648\u0627\u0642\u0639\u06c1 \u0628\u0633<\/td>\n<td>\u062e\u0631\u06af\u0648\u0634 \u0627\u06cc\u0645 \u06a9\u06cc\u0648<\/td>\n<\/tr>\n<tr>\n<td>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633<\/td>\n<td>\u067e\u0648\u0633\u0679\u06af\u0631\u06cc \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644<\/td>\n<\/tr>\n<tr>\n<td>API \u06a9\u06cc \u0646\u0645\u0627\u0626\u0634<\/td>\n<td>API \u06af\u06cc\u0679 \u0648\u06d2 (HTTP)<\/td>\n<\/tr>\n<tr>\n<td>\u06a9\u0646\u0679\u06cc\u0646\u0631\u0627\u0626\u0632\u06cc\u0634\u0646<\/td>\n<td>docker-compose<\/td>\n<\/tr>\n<tr>\n<td>\u067e\u06d2 \u067e\u0627\u0644 API<\/td>\n<td>\u0622\u0631\u0688\u0631\u0632 v2 (\u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u06cc\u06ba\u060c \u0645\u0646\u0638\u0648\u0631 \u06a9\u0631\u06cc\u06ba\u060c \u06a9\u06cc\u067e\u0686\u0631 \u06a9\u0631\u06cc\u06ba)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"heading-why-use-a-dedicated-payment-service\">\u0627\u06cc\u06a9 \u0648\u0642\u0641 \u0634\u062f\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06cc\u0648\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u061f<\/h2>\n<p>\u0627\u06cc\u06a9 \u0648\u0642\u0641 \u0634\u062f\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642\u06c1 \u062a\u0645\u0627\u0645 \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc\u0648\u06ba \u06a9\u0648 \u0627\u06cc\u06a9 \u062c\u06af\u06c1 \u067e\u0631 \u0645\u0631\u06a9\u0632\u06cc\u062a \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 PayPal \u0633\u06d2 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0628\u0627\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2\u060c \u0622\u067e \u0635\u0631\u0641 \u0627\u067e\u0646\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0633\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0622\u067e\u0631\u06cc\u0634\u0646 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0633\u0631\u0648\u0633 \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642\u060c \u0622\u0631\u0688\u0631 \u06a9\u06cc \u062a\u062e\u0644\u06cc\u0642\u060c \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u06af\u0631\u0641\u062a\u0627\u0631\u06cc\u060c \u0648\u0627\u0644\u06cc\u0679 \u0627\u067e \u0688\u06cc\u0679\u0633\u060c \u0644\u06cc\u062c\u0631 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0632\u060c \u0627\u0648\u0631 \u0648\u06cc\u0628 \u06c1\u06a9 \u067e\u0631\u0648\u0633\u06cc\u0633\u0646\u06af \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u062f\u0631\u06cc\u06ba \u0627\u062b\u0646\u0627\u060c \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0645\u0646\u0637\u0642 \u067e\u0631 \u062a\u0648\u062c\u06c1 \u0645\u0631\u06a9\u0648\u0632 \u06a9\u0631\u062a\u06cc \u0631\u06c1\u062a\u06cc \u06c1\u06cc\u06ba \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0637\u0644\u0628\u0627\u0621 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u06cc\u0627 \u0633\u0628\u0633\u06a9\u0631\u067e\u0634\u0646\u0632\u06d4<\/p>\n<p>\u0622\u067e \u06a9\u06cc \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u06a9\u0648 \u0635\u0631\u0641 \u062f\u0631\u062c \u0630\u06cc\u0644 \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2:<\/p>\n<ol>\n<li>\n<p>\u06a9\u062a\u0646\u0627 \u0686\u0627\u0631\u062c \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u06a9\u0648\u0646 \u0627\u062f\u0627 \u06a9\u0631 \u0631\u06c1\u0627 \u06c1\u06d2<\/p>\n<\/li>\n<li>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0627\u06c1\u0644 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631 (<code>referenceId<\/code>)<\/p>\n<\/li>\n<li>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0628\u0639\u062f \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u06a9\u06c1\u0627\u06ba \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 \u06a9\u0631\u0646\u0627 \u06c1\u06d2 (<code>returnUrl<\/code> \/ <code>cancelUrl<\/code>)<\/p>\n<\/li>\n<\/ol>\n<p>\u0648\u06c1 \u06c1\u06cc\u06ba <strong>~ \u0646\u06c1\u06cc\u06ba<\/strong> \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06cc \u0627\u0633\u0646\u0627\u062f \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-architecture-overview\">\u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u0627 \u062c\u0627\u0626\u0632\u06c1<\/h2>\n<p>\u0635\u0627\u0631\u0641 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u067e\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0648 API \u06af\u06cc\u0679 \u0648\u06d2 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0637\u0644\u0628\u0627\u0621 \u06a9\u06cc \u062e\u062f\u0645\u0627\u062a \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0633\u0631\u0648\u0633 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 gRPC \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u062c\u0648 PayPal \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062a\u0645\u0627\u0645 \u062a\u0639\u0627\u0645\u0644\u0627\u062a \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u062c\u0628 \u06a9\u0648\u0626\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0645\u06a9\u0645\u0644 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u060c \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a RabbitMQ \u067e\u0631 \u0627\u06cc\u06a9 \u0648\u0627\u0642\u0639\u06c1 \u0634\u0627\u0626\u0639 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u062c\u0633 \u0633\u06d2 \u0637\u0627\u0644\u0628 \u0639\u0644\u0645 \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u0648 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0635\u0648\u0631\u062a\u062d\u0627\u0644 \u06a9\u0648 \u0645\u062a\u0636\u0627\u062f \u0637\u0648\u0631 \u067e\u0631 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0645\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\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\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                     PRESENTATION LAYER                     \u2502\n\u251c\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Frontend (React)                                           \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\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                        \u2502 HTTP\n                        \u25bc\n\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                       GATEWAY LAYER                        \u2502\n\u251c\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 student-apigw                                               \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\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                        \u2502 gRPC\n                        \u25bc\n\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                       DOMAIN LAYER                         \u2502\n\u251c\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 students-service                                            \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\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                        \u2502 gRPC\n                        \u25bc\n\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                      PAYMENT LAYER                         \u2502\n\u251c\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 payment-service                                             \u2502\n\u2502                                                            \u2502\n\u2502 \u2022 Create Payment                                           \u2502\n\u2502 \u2022 Capture Payment                                          \u2502\n\u2502 \u2022 Wallet Management                                        \u2502\n\u2502 \u2022 Ledger                                                   \u2502\n\u2502 \u2022 Webhooks                                                 \u2502\n\u2502 \u2022 Event Publishing                                         \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\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\u2518\n               \u2502                       \u2502\n               \u2502 REST                  \u2502 RabbitMQ\n               \u25bc                       \u25bc\n\n      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n      \u2502    PayPal     \u2502      \u2502   payment_events   \u2502\n      \u2502   Checkout    \u2502      \u2502       Queue        \u2502\n      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                       \u2502\n                                       \u25bc\n\n                           \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                           \u2502 students-service   \u2502\n                           \u2502 Event Consumer     \u2502\n                           \u2514\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<h3 id=\"heading-payment-state-machine\">\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0631\u06cc\u0627\u0633\u062a \u0645\u0634\u06cc\u0646<\/h3>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u06cc \u0645\u0634\u06cc\u0646 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0644\u0627\u0626\u0641 \u0633\u0627\u0626\u06cc\u06a9\u0644 \u06a9\u06cc \u0646\u0645\u0627\u0626\u0646\u062f\u06af\u06cc \u06a9\u0631\u062a\u06cc \u06c1\u06d2 \u0627\u0648\u0631 \u062a\u062e\u0644\u06cc\u0642 \u0633\u06d2 \u0644\u06d2 \u06a9\u0631 \u062a\u06a9\u0645\u06cc\u0644 (\u06cc\u0627 \u0646\u0627\u06a9\u0627\u0645\u06cc) \u062a\u06a9 \u0627\u0633 \u06a9\u06cc \u067e\u06cc\u0634\u0631\u0641\u062a \u06a9\u0648 \u0679\u0631\u06cc\u06a9 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u06c1\u0631 \u062d\u06cc\u062b\u06cc\u062a \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0645\u0648\u062c\u0648\u062f\u06c1 \u062d\u0627\u0644\u062a \u06a9\u06cc \u0639\u06a9\u0627\u0633\u06cc \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u062c\u0633 \u0633\u06d2 \u0646\u06af\u0631\u0627\u0646\u06cc \u06a9\u0631\u0646\u0627\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u0646\u0627 \u0627\u0648\u0631 \u063a\u0644\u0637 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u0648 \u0631\u0648\u06a9\u0646\u0627 \u0622\u0633\u0627\u0646 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">NOT_STARTED \u2192 EXECUTING \u2192 SUCCESS\n                      \u2514\u2192 FAILED\n<\/code><\/pre>\n<ul>\n<li>\n<p><strong>NOT_STARTED<\/strong> &#8211; \u0688\u06cc \u0628\u06cc \u0645\u06cc\u06ba \u0622\u0631\u0688\u0631 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/strong> &#8211; \u0622\u067e \u06a9\u0627 \u067e\u06d2 \u067e\u0627\u0644 \u0622\u0631\u0688\u0631 \u0628\u0646\u0627 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0645\u0646\u0638\u0648\u0631\u06cc \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u06a9\u0627\u0645\u06cc\u0627\u0628\u06cc<\/strong> &#8211; \u0641\u0646\u0688\u0632 \u062c\u0645\u0639 \u06a9\u0631\u06cc\u06ba\u060c \u0644\u06cc\u062c\u0631 \u06a9\u0648 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u060c \u0627\u06cc\u0648\u0646\u0679\u0633 \u067e\u0648\u0633\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0646\u0627\u06a9\u0627\u0645<\/strong> \u2014 \u06a9\u06cc\u067e\u0686\u0631 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u06af\u06cc\u0627 \u06cc\u0627 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0645\u0646\u0633\u0648\u062e \u06a9\u0631 \u062f\u06cc\u0627 \u06af\u06cc\u0627\u06d4<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0637\u06cc\u06ba<\/h2>\n<p>\u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba:<\/p>\n<h2 id=\"heading-paypal-concepts-you-need-to-know\">\u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06d2 \u062a\u0635\u0648\u0631\u0627\u062a \u062c\u0648 \u0622\u067e \u06a9\u0648 \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/h2>\n<p>PayPal \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0686\u0646\u062f \u0627\u06c1\u0645 \u062a\u0635\u0648\u0631\u0627\u062a \u06a9\u0648 \u0633\u0645\u062c\u06be\u0646\u0627 \u0645\u062f\u062f\u06af\u0627\u0631 \u06c1\u06d2\u06d4 PayPal \u0627\u06cc\u06a9 \u0622\u0631\u0688\u0631 \u067e\u0631 \u0645\u0628\u0646\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062a\u0631\u0642\u06cc \u0627\u0648\u0631 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0644\u06af \u0645\u0627\u062d\u0648\u0644 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0633 \u06a9\u06cc \u0627\u06cc\u067e\u0644\u06cc \u06a9\u06cc\u0634\u0646 \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-sandbox-vs-live\">\u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u0628\u0645\u0642\u0627\u0628\u0644\u06c1 \u0644\u0627\u0626\u06cc\u0648<\/h3>\n<table>\n<thead>\n<tr>\n<th>\u0645\u0627\u062d\u0648\u0644<\/th>\n<th>API \u0628\u06cc\u0633 \u06cc\u0648 \u0622\u0631 \u0627\u06cc\u0644<\/th>\n<th>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0627 URL<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 (\u0688\u06cc\u0648\u0644\u067e\u0631)<\/td>\n<td><code>https:\/\/api-m.sandbox.paypal.com<\/code><\/td>\n<td><code>https:\/\/www.sandbox.paypal.com\/checkoutnow?token=...<\/code><\/td>\n<\/tr>\n<tr>\n<td>\u0644\u0627\u0626\u06cc\u0648 (\u067e\u06cc\u062f\u0627\u0648\u0627\u0631)<\/td>\n<td><code>https:\/\/api-m.paypal.com<\/code><\/td>\n<td><code>https:\/\/www.paypal.com\/checkoutnow?token=...<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u06c1\u0645\u06cc\u0634\u06c1 \u062a\u0631\u0642\u06cc \u067e\u0630\u06cc\u0631 <strong>\u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633<\/strong>. \u0635\u0631\u0641 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u0645\u06cc\u06ba \u0644\u0627\u0626\u06cc\u0648 \u062c\u0627\u0624.<\/p>\n<h3 id=\"heading-orders-api-flow-what-we-use\">\u0622\u0631\u0688\u0631\u0632 API \u0641\u0644\u0648 (\u062c\u0648 \u06c1\u0645 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba)<\/h3>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06d2 \u0622\u0631\u0688\u0631\u0632 v2 API \u062a\u06cc\u0646 \u0645\u0631\u0627\u062d\u0644 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2:<\/p>\n<ol>\n<li>\n<p><strong>\u0622\u0631\u0688\u0631 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/strong>: \u067e\u0633\u062f\u06cc\u062f \u0631\u0642\u0645 \u0627\u0648\u0631 \u0648\u0627\u067e\u0633\u06cc URL \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u06a9 \u0622\u0631\u0688\u0631 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0645\u0646\u0638\u0648\u0631 \u06a9\u0631\u0646\u0627<\/strong>: \u0635\u0627\u0631\u0641 \u06a9\u0648 \u067e\u06d2 \u067e\u0627\u0644 \u067e\u0631 \u0628\u06be\u06cc\u062c \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0642\u0628\u0636\u06c1<\/strong>: \u067e\u0633\u062f\u06cc\u062f \u0645\u0646\u0638\u0648\u0631 \u0634\u062f\u06c1 \u0641\u0646\u0688\u0632 \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<\/ol>\n<p>\u06cc\u06c1 \u06af\u0632\u0634\u062a\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc\u0648\u06ba \u06a9\u06d2 REST API \u0633\u06d2 \u0645\u062e\u062a\u0644\u0641 \u06c1\u06d2\u06d4 \u0622\u0631\u0688\u0631\u0632 v2 \u0646\u0626\u06d2 \u0627\u0646\u0636\u0645\u0627\u0645 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062f\u06c1 \u0637\u0631\u06cc\u0642\u06c1 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-environment-variables\">\u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a<\/h3>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u0633\u0631\u0648\u0633 \u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u0633\u06d2 \u0627\u067e\u0646\u06cc \u062a\u0631\u062a\u06cc\u0628 \u067e\u0691\u06be\u062a\u06cc \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u0633\u0648\u0631\u0633 \u06a9\u0648\u0688 \u0645\u06cc\u06ba \u062d\u0633\u0627\u0633 \u0627\u0633\u0646\u0627\u062f \u06a9\u06cc \u062d\u0641\u0627\u0638\u062a \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u0627\u0648\u0631 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0645\u0627\u062d\u0648\u0644 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0622\u0633\u0627\u0646\u06cc \u0633\u06d2 \u0645\u0646\u062a\u0642\u0644\u06cc \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-bash\">PAYPAL_CLIENT_ID=your_client_id\nPAYPAL_CLIENT_SECRET=your_client_secret\nPAYPAL_API_BASE=https:\/\/api-m.sandbox.paypal.com   # or https:\/\/api-m.paypal.com for live\n<\/code><\/pre>\n<p>\u0627\u067e\u0646\u06cc \u0627\u0635\u0644 \u0627\u0633\u0646\u0627\u062f Git \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0646\u06c1 \u062f\u06cc\u06ba\u06d4 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba <code>.env<\/code> \u0641\u0627\u0626\u0644 \u0627\u0648\u0631 \u0688\u0648\u06a9\u0631 \u0645\u0627\u062d\u0648\u0644 \u06a9\u0627 \u0627\u0646\u062c\u06cc\u06a9\u0634\u0646\u06d4<\/p>\n<h2 id=\"heading-project-structure\">\u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u0633\u0627\u062e\u062a<\/h2>\n<pre><code class=\"language-plaintext\">apps\/\n\u251c\u2500\u2500 core\/\n\u2502   \u2514\u2500\u2500 payment-service\/          # Owns all PayPal logic\n\u2502       \u251c\u2500\u2500 src\/\n\u2502       \u2502   \u251c\u2500\u2500 app\/payment\/\n\u2502       \u2502   \u2502   \u251c\u2500\u2500 paypal\/paypal.service.ts\n\u2502       \u2502   \u2502   \u251c\u2500\u2500 payment.service.ts\n\u2502       \u2502   \u2502   \u251c\u2500\u2500 payment.grpc.controller.ts\n\u2502       \u2502   \u2502   \u251c\u2500\u2500 payment.http.controller.ts\n\u2502       \u2502   \u2502   \u2514\u2500\u2500 events\/payment-events.publisher.ts\n\u2502       \u2502   \u251c\u2500\u2500 migrations\/       # DB schema\n\u2502       \u2502   \u2514\u2500\u2500 routes\/health.routes.ts\n\u2502       \u2514\u2500\u2500 Dockerfile\n\u251c\u2500\u2500 services\/\n\u2502   \u2514\u2500\u2500 students-service\/         # Domain service example\n\u2502       \u2514\u2500\u2500 src\/app\/payment\/\n\u2502           \u251c\u2500\u2500 payment-client.service.ts      # gRPC client\n\u2502           \u251c\u2500\u2500 application-payment.service.ts # business logic\n\u2502           \u2514\u2500\u2500 payment-events.consumer.ts     # RabbitMQ listener\n\u2514\u2500\u2500 gateways\/\n    \u2514\u2500\u2500 student-apigw\/            # HTTP API for frontend\nlibs\/\n\u2514\u2500\u2500 shared\/dto\/src\/lib\/payment\/\n    \u2514\u2500\u2500 payment.proto             # Shared gRPC contract\n<\/code><\/pre>\n<h2 id=\"heading-step-1-create-the-payment-service\">\u0645\u0631\u062d\u0644\u06c1 1 &#8211; \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h2>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u06cc\u06a9 \u0639\u0645\u0644 \u0645\u06cc\u06ba \u062f\u0648 \u0633\u0631\u0648\u0631 \u0686\u0644\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<table>\n<thead>\n<tr>\n<th>\u06a9\u0648\u0688<\/th>\n<th>\u0628\u0646\u062f\u0631\u06af\u0627\u06c1<\/th>\n<th>\u0645\u0642\u0635\u062f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>HTTP<\/td>\n<td>3003<\/td>\n<td>\u06c1\u06cc\u0644\u062a\u06be \u0686\u06cc\u06a9\u0633\u060c \u0648\u06cc\u0628 \u06c1\u06a9\u0633\u060c \u0627\u0648\u0631 \u0645\u06cc\u0646\u062c\u0645\u0646\u0679 APIs<\/td>\n<\/tr>\n<tr>\n<td>\u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc<\/td>\n<td>50061<\/td>\n<td>\u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u06a9\u0627\u0644\u0632<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u06cc\u06a9 \u06c1\u06cc NestJS \u0627\u06cc\u067e\u0644\u06cc\u06a9\u06cc\u0634\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 HTTP \u0633\u0631\u0648\u0631 \u0627\u0648\u0631 \u0627\u06cc\u06a9 gRPC \u0633\u0631\u0648\u0631 \u062f\u0648\u0646\u0648\u06ba \u06a9\u0648 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u0627\u06cc\u0686 \u0679\u06cc \u0679\u06cc \u067e\u06cc \u0633\u0631\u0648\u0631\u0632 \u06c1\u06cc\u0644\u062a\u06be \u0686\u06cc\u06a9\u0633\u060c \u0648\u06cc\u0628 \u06c1\u06a9\u0633 \u0627\u0648\u0631 \u0628\u06cc\u0631\u0648\u0646\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u0628 \u06a9\u06c1 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u0633\u0631\u0648\u0631 \u062f\u06cc\u06af\u0631 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0633\u06d2 \u062f\u0627\u062e\u0644\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u0642\u0628\u0648\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">\n\/\/ apps\/core\/payment-service\/src\/main.ts\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n\n  \/\/ Health route (outside \/api prefix)\n  app.use('\/health', healthRouter);\n\n  \/\/ gRPC microservice\n  app.connectMicroservice<microserviceoptions>({\n    transport: Transport.GRPC,\n    options: {\n      package: 'payment',\n      protoPath: join(process.cwd(), 'libs\/shared\/dto\/src\/lib\/payment\/payment.proto'),\n      url: `0.0.0.0:${process.env.GRPC_PORT || '50061'}`,\n    },\n  });\n\n  app.setGlobalPrefix('api');\n  await app.startAllMicroservices();\n  await app.listen(process.env.PORT || 3003);\n}\n<\/microserviceoptions><\/code><\/pre>\n<p>\u0622\u063a\u0627\u0632 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c NestJS \u062f\u0648\u0646\u0648\u06ba \u0633\u0631\u0648\u0631\u0632 \u06a9\u0648 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062a\u0627\u06a9\u06c1 \u0628\u06cc\u0631\u0648\u0646\u06cc \u06a9\u0644\u0627\u0626\u0646\u0679\u0633 \u0627\u0648\u0631 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u062e\u062f\u0645\u0627\u062a \u0645\u0646\u0627\u0633\u0628 \u067e\u0631\u0648\u0679\u0648\u06a9\u0648\u0644 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631 \u0633\u06a9\u06cc\u06ba\u06d4<\/p>\n<p><strong>\u06a9\u0644\u06cc\u062f\u06cc \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u06d2 \u0627\u0646\u062a\u062e\u0627\u0628:<\/strong> HTTP \u0628\u06cc\u0631\u0648\u0646\u06cc\/\u0648\u06cc\u0628 \u06c1\u064f\u06a9 \u0679\u0631\u06cc\u0641\u06a9 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06c1\u06d2\u06d4 gRPC \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062a\u06cc\u0632 \u0627\u0646 \u067e\u0679 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u06a9\u0627\u0644\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-step-2-define-the-grpc-contract\">\u0645\u0631\u062d\u0644\u06c1 2 &#8211; \u0627\u06cc\u06a9 gRPC \u0645\u0639\u0627\u06c1\u062f\u06c1 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0627\u06af\u0644\u0627\u060c \u0627\u06cc\u06a9 \u062d\u0635\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba. <code>.proto<\/code> \u0627\u06cc\u06a9 \u0641\u0627\u0626\u0644 \u0644\u06a9\u06be\u06cc\u06ba \u062a\u0627\u06a9\u06c1 \u062a\u0645\u0627\u0645 \u062e\u062f\u0645\u0627\u062a \u0627\u06cc\u06a9 \u06c1\u06cc \u0632\u0628\u0627\u0646 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>gRPC \u0645\u0639\u0627\u06c1\u062f\u06d2 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0627\u0634\u062a\u0631\u0627\u06a9 \u06a9\u0631\u062f\u06c1 APIs \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 <code>.proto<\/code> \u0641\u0627\u0626\u0644 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u06cc \u06c1\u06d2 \u06a9\u06c1 \u062a\u0645\u0627\u0645 \u062e\u062f\u0645\u0627\u062a\u060c \u067e\u0631\u0648\u06af\u0631\u0627\u0645\u0646\u06af \u0632\u0628\u0627\u0646 \u0633\u06d2 \u0642\u0637\u0639 \u0646\u0638\u0631\u060c \u0627\u06cc\u06a9 \u06c1\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0627\u0648\u0631 \u062c\u0648\u0627\u0628\u06cc \u0688\u06be\u0627\u0646\u0686\u06d2 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-protobuf\">\/\/ libs\/shared\/dto\/src\/lib\/payment\/payment.proto\n\nsyntax = \"proto3\";\npackage payment;\n\nservice PaymentService {\n  rpc CreatePayment(CreatePaymentRequest) returns (CreatePaymentResponse) {}\n  rpc CapturePayment(CapturePaymentRequest) returns (CapturePaymentResponse) {}\n  rpc GetPaymentStatus(GetPaymentStatusRequest) returns (GetPaymentStatusResponse) {}\n  rpc ListPayments(ListPaymentsRequest) returns (ListPaymentsResponse) {}\n}\n\nmessage CreatePaymentRequest {\n  string checkout_id = 1;\n  string payment_order_id = 2;\n  string domain = 3;           \/\/ e.g. \"application\", \"subscription\"\n  string reference_id = 4;     \/\/ business entity ID\n  string payer_id = 5;\n  string amount = 6;\n  string currency = 7;\n  string buyer_email = 8;\n  string seller_account = 9;\n  string payment_category = 10;\n  string return_url = 11;      \/\/ PayPal redirect on success\n  string cancel_url = 12;      \/\/ PayPal redirect on cancel\n  string idempotency_key = 13;\n  string metadata = 14;\n  string description = 15;\n}\n\nmessage CreatePaymentResponse {\n  int32 status = 1;\n  string message = 2;\n  string payment_order_id = 3;\n  string paypal_order_id = 4;\n  string approve_url = 5;      \/\/ Redirect user here\n  string payment_order_status = 6;\n}\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>domain<\/code> + <code>reference_id<\/code> \u062c\u0648\u0691\u0627 \u0627\u06cc\u06a9 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u0648 \u06a9\u0633\u06cc \u0627\u06cc\u06a9 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0645\u0627\u0688\u0644 \u0645\u06cc\u06ba \u06cc\u06a9\u062c\u0627 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba\u060c \u0633\u0628\u0633\u06a9\u0631\u067e\u0634\u0646\u0632\u060c \u06a9\u0627\u0644\u062c \u0679\u06cc\u0648\u0634\u0646 \u0648\u063a\u06cc\u0631\u06c1 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc\u0648\u06ba \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-step-3-implement-the-paypal-service\">\u0645\u0631\u062d\u0644\u06c1 3 &#8211; \u067e\u06d2 \u067e\u0627\u0644 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0648 \u0644\u0627\u06af\u0648 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0627\u0628 \u0635\u0631\u0641 <code>PayPalService<\/code> \u06cc\u06c1 PayPal REST API \u06a9\u0648 \u0644\u067e\u06cc\u0679 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u067e\u0646\u06cc \u067e\u0648\u0631\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0645\u06cc\u06ba PayPal APIs \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0622\u067e \u062a\u0645\u0627\u0645 PayPal \u06a9\u0645\u06cc\u0648\u0646\u06cc\u06a9\u06cc\u0634\u0646 \u06a9\u0648 \u0627\u06cc\u06a9 \u0648\u0642\u0641 \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u0633\u0645\u06cc\u0679 \u0644\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u062a\u0635\u062f\u06cc\u0642\u060c \u0622\u0631\u0688\u0631 \u06a9\u06cc \u062a\u062e\u0644\u06cc\u0642\u060c \u0627\u0648\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u06af\u0631\u0641\u062a \u06a9\u06cc \u0645\u0646\u0637\u0642 \u06a9\u0648 \u0645\u0631\u06a9\u0632\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u06c1\u06cc\u06ba \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u0646\u0627 \u0622\u0633\u0627\u0646 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ apps\/core\/payment-service\/src\/app\/payment\/paypal\/paypal.service.ts\n\n@Injectable()\nexport class PayPalService {\n  private accessToken: string | null = null;\n  private tokenExpiresAt = 0;\n\n  private get apiBase(): string {\n    return this.configService.get('PAYPAL_API_BASE')\n      || 'https:\/\/api-m.sandbox.paypal.com';\n  }\n\n  \/\/ Step 1: Get OAuth access token (cached until expiry)\n  private async getAccessToken(): Promise<string> {\n    const now = Date.now();\n    if (this.accessToken && now < this.tokenExpiresAt) {\n      return this.accessToken;\n    }\n\n    const response = await axios.post(\n      `${this.apiBase}\/v1\/oauth2\/token`,\n      'grant_type=client_credentials',\n      {\n        auth: {\n          username: this.configService.get('PAYPAL_CLIENT_ID'),\n          password: this.configService.get('PAYPAL_CLIENT_SECRET'),\n        },\n        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n      }\n    );\n\n    this.accessToken = response.data.access_token;\n    this.tokenExpiresAt = now + (response.data.expires_in - 60) * 1000;\n    return this.accessToken;\n  }\n\n  \/\/ Step 2: Create PayPal checkout order\n  async createOrder(input: PayPalCreateOrderInput) {\n    const token = await this.getAccessToken();\n\n    const response = await axios.post(\n      `${this.apiBase}\/v2\/checkout\/orders`,\n      {\n        intent: 'CAPTURE',\n        purchase_units: [{\n          custom_id: input.paymentOrderId,\n          description: input.description,\n          amount: {\n            currency_code: input.currency,\n            value: input.amount,\n          },\n        }],\n        application_context: {\n          return_url: input.returnUrl,\n          cancel_url: input.cancelUrl,\n          brand_name: 'YourApp',\n          user_action: 'PAY_NOW',\n        },\n      },\n      {\n        headers: {\n          Authorization: `Bearer ${token}`,\n          'PayPal-Request-Id': input.idempotencyKey,\n        },\n      }\n    );\n\n    const paypalOrderId = response.data.id;\n    const approveUrl = response.data.links\n      ?.find((l) => l.rel === 'approve')?.href;\n\n    return { paypalOrderId, approveUrl };\n  }\n\n  \/\/ Step 3: Capture approved order\n  async captureOrder(paypalOrderId: string) {\n    const token = await this.getAccessToken();\n\n    const response = await axios.post(\n      `${this.apiBase}\/v2\/checkout\/orders\/${paypalOrderId}\/capture`,\n      {},\n      { headers: { Authorization: `Bearer ${token}` } }\n    );\n\n    const capture = response.data.purchase_units?.[0]?.payments?.captures?.[0];\n    return { status: response.data.status, captureId: capture?.id || '' };\n  }\n}\n<\/string><\/code><\/pre>\n<p>\u0627\u067e\u0646\u06cc \u06a9\u0646\u0641\u06cc\u06af\u0631\u06cc\u0634\u0646 (\u0628\u0634\u0645\u0648\u0644 \u0646\u0642\u0627\u0628 \u067e\u0648\u0634 \u0631\u0627\u0632) \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u0631\u06cc\u06ba \u062a\u0627\u06a9\u06c1 \u0622\u067e \u0627\u06cc\u06a9 \u0646\u0638\u0631 \u0645\u06cc\u06ba \u062f\u06cc\u06a9\u06be \u0633\u06a9\u06cc\u06ba \u06a9\u06c1 \u0622\u067e \u06a9\u0627 \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u0627\u0648\u0631 \u0644\u0627\u0626\u06cc\u0648 \u0634\u0631\u0648\u0639 \u06c1\u0648\u0646\u06d2 \u067e\u0631 \u06a9\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">PayPal configuration check:\n  PAYPAL_API_BASE: https:\/\/api-m.paypal.com\n  PAYPAL_CLIENT_ID: AQb2...aq1M (80 chars)\n  credentialsPresent: true\n  environment: live\n<\/code><\/pre>\n<p>\u0631\u0633\u0627\u0626\u06cc \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u0645\u06cc\u0639\u0627\u062f \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u062a\u06a9 \u06a9\u06cc\u0634 \u06a9\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u06a9\u0627\u0631\u06a9\u0631\u062f\u06af\u06cc \u06a9\u0648 \u0628\u06c1\u062a\u0631 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u0631 \u0628\u0627\u0631 \u062c\u0628 \u0622\u067e \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u0646\u0626\u06d2 OAuth \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06a9\u0648 \u062e\u062a\u0645 \u06a9\u0631\u06a9\u06d2 \u063a\u06cc\u0631 \u0636\u0631\u0648\u0631\u06cc API \u06a9\u0627\u0644\u0632 \u06a9\u0648 \u06a9\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-step-4-build-the-payment-flow-create-approve-capture\">\u0645\u0631\u062d\u0644\u06c1 4 &#8211; \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0627 \u0628\u06c1\u0627\u0624 \u0628\u0646\u0627\u0626\u06cc\u06ba (\u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u06cc\u06ba\u060c \u0645\u0646\u0638\u0648\u0631 \u06a9\u0631\u06cc\u06ba\u060c \u06a9\u06cc\u067e\u0686\u0631 \u06a9\u0631\u06cc\u06ba)<\/h2>\n<h3 id=\"heading-create-payment\">\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<p><code>PaymentService.createPayment()<\/code>    \u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0627\u0645 \u06a9\u0631\u06cc\u06ba:<\/p>\n<ol>\n<li>\n<p>\u0686\u06cc\u06a9\u0631 <strong>\u0628\u06d2 \u0636\u0645\u06cc\u0631 \u06a9\u0644\u06cc\u062f<\/strong> \u0645\u0648\u062c\u0648\u062f\u06c1 \u0622\u0631\u0688\u0631 \u06a9\u0648 \u0644\u0648\u0679\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u06af\u0631 \u06cc\u06c1 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u0628\u0646 \u0686\u06a9\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0646\u0633\u0644 <code>payment_events<\/code> \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062a\u0627\u0631\u06cc\u062e<\/p>\n<\/li>\n<li>\n<p>\u0646\u0633\u0644 <code>payment_orders<\/code> \u062d\u06cc\u062b\u06cc\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0642\u0637\u0627\u0631\u06cc\u06ba <code>NOT_STARTED<\/code><\/p>\n<\/li>\n<li>\n<p>\u06a9\u0627\u0644 <code>PayPalService.createOrder()<\/code><\/p>\n<\/li>\n<li>\n<p>\u0627\u067e\u0646\u06d2 \u0622\u0631\u0688\u0631 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u06a9\u0648 \u0627\u0633 \u067e\u0631 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u06cc\u06ba: <code>EXECUTING<\/code><\/p>\n<\/li>\n<li>\n<p>\u0631\u067e\u0648\u0631\u0679 <code>approveUrl<\/code> \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06a9\u0648<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"language-typescript\">async createPayment(input: CreatePaymentPayload) {\n  \/\/ Idempotency: prevent duplicate charges\n  const existing = await this.paymentOrderModel.findOne({\n    where: { idempotencyKey: input.idempotencyKey },\n  });\n  if (existing) return this.buildCreateResponse(existing);\n\n  const order = await this.paymentOrderModel.create({\n    paymentOrderId: input.paymentOrderId,\n    amount: input.amount,\n    currency: input.currency,\n    paymentOrderStatus: PaymentOrderStatus.NOT_STARTED,\n    domain: input.domain,\n    referenceId: input.referenceId,\n    \/\/ ...\n  });\n\n  const paypalOrder = await this.paypalService.createOrder({\n    paymentOrderId: order.paymentOrderId,\n    amount: input.amount,\n    currency: input.currency,\n    returnUrl: input.returnUrl,\n    cancelUrl: input.cancelUrl,\n    idempotencyKey: input.idempotencyKey,\n  });\n\n  await order.update({\n    paymentOrderStatus: PaymentOrderStatus.EXECUTING,\n    paypalOrderId: paypalOrder.paypalOrderId,\n  });\n\n  return {\n    approveUrl: paypalOrder.approveUrl,\n    paypalOrderId: paypalOrder.paypalOrderId,\n    paymentOrderStatus: PaymentOrderStatus.EXECUTING,\n  };\n}\n<\/code><\/pre>\n<h3 id=\"heading-user-approves-on-paypal\">\u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06c1 \u0645\u0646\u0638\u0648\u0631 \u0634\u062f\u06c1 \u0635\u0627\u0631\u0641<\/h3>\n<p>\u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>approveUrl<\/code>. \u067e\u06d2 \u067e\u0627\u0644 \u062a\u0635\u062f\u06cc\u0642 \u0627\u0648\u0631 \u0627\u062c\u0627\u0632\u062a \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631\u06d2 \u06af\u0627 \u0627\u0648\u0631 \u067e\u06be\u0631 \u0622\u067e \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0628\u06be\u06cc\u062c\u06d2 \u06af\u0627\u06d4 <code>returnUrl<\/code>.<\/p>\n<h3 id=\"heading-capture-payment\">\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u06af\u0631\u0641\u062a\u0627\u0631\u06cc<\/h3>\n<p>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0645\u0646\u0638\u0648\u0631\u06cc \u06a9\u06d2 \u0628\u0639\u062f \u0645\u062c\u06be\u06d2 \u06a9\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>capturePayment()<\/code> \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0637\u0631\u062d <code>paymentOrderId<\/code> \u06cc\u0627 <code>paypalOrderId<\/code>:<\/p>\n<pre><code class=\"language-typescript\">async capturePayment(paymentOrderId?: string, paypalOrderId?: string) {\n  const order = await this.findOrder(paymentOrderId, paypalOrderId);\n\n  if (order.paymentOrderStatus === PaymentOrderStatus.SUCCESS) {\n    return this.buildCaptureResponse(order); \/\/ already captured\n  }\n\n  const capture = await this.paypalService.captureOrder(order.paypalOrderId);\n\n  if (capture.status !== 'COMPLETED') {\n    throw new Error(`PayPal capture status: ${capture.status}`);\n  }\n\n  await this.finalizeSuccessfulPayment(order, capture.captureId);\n  return this.buildCaptureResponse(order);\n}\n<\/code><\/pre>\n<p><code>finalizeSuccessfulPayment()<\/code>    \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0645\u06cc\u06ba \u0686\u0644\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<ol>\n<li>\n<p>\u0627\u067e\u0646\u06d2 \u0622\u0631\u0688\u0631 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u06a9\u0648 \u0627\u0633 \u067e\u0631 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u06cc\u06ba: <code>SUCCESS<\/code><\/p>\n<\/li>\n<li>\n<p>\u0645\u0631\u0686\u0646\u0679 \u0648\u0627\u0644\u06cc\u0679 \u06a9\u0627 \u0628\u06cc\u0644\u0646\u0633 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0644\u06cc\u062c\u0631 \u0627\u0646\u062f\u0631\u0627\u062c\u0627\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba (\u0622\u0688\u0679 \u0679\u0631\u06cc\u0644)<\/p>\n<\/li>\n<li>\n<p>\u0686\u06cc\u06a9 \u0622\u0624\u0679 \u0627\u06cc\u0648\u0646\u0679 \u06a9\u0648 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u0646\u0634\u0627\u0646 \u0632\u062f \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u067e\u0648\u0633\u0679 <code>payment.{domain}.completed<\/code> RabbitMQ \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a<\/p>\n<\/li>\n<\/ol>\n<h2 id=\"heading-step-5-connect-domain-services-via-grpc\">\u0645\u0631\u062d\u0644\u06c1 5 &#8211; \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0648 gRPC \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633\u0632\u060c \u062c\u06cc\u0633\u06d2 <code>students-service<\/code>) \u06a9\u0628\u06be\u06cc \u0628\u06be\u06cc \u067e\u06d2 \u067e\u0627\u0644 \u0633\u06d2 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0628\u0627\u062a \u0646\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u0644\u0627\u0626\u0646\u0679 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>\u0637\u0627\u0644\u0628 \u0639\u0644\u0645 \u06a9\u06cc \u062e\u062f\u0645\u062a \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u0644\u0627\u0626\u0646\u0679 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 PayPal API \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0622\u067e \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06c1 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062f\u06c1 \u0633\u062e\u062a\u06cc \u0633\u06d2 \u0679\u0627\u0626\u067e \u0634\u062f\u06c1 \u0631\u06cc\u0645\u0648\u0679 \u0637\u0631\u06cc\u0642\u06c1 \u06a9\u0627\u0631 \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ apps\/services\/students-service\/src\/app\/payment\/payment.module.ts\n\nClientsModule.registerAsync([{\n  name: 'PAYMENT_SERVICE',\n  useFactory: () => ({\n    transport: Transport.GRPC,\n    options: {\n      package: 'payment',\n      protoPath: 'libs\/shared\/dto\/src\/lib\/payment\/payment.proto',\n      url: process.env.PAYMENT_SERVICE_URL || 'payment-service:50061',\n    },\n  }),\n}])\n<\/code><\/pre>\n<pre><code class=\"language-typescript\">\/\/ payment-client.service.ts\n\n@Injectable()\nexport class PaymentClientService implements OnModuleInit {\n  private paymentService: PaymentGrpcService;\n\n  constructor(@Inject('PAYMENT_SERVICE') private client: ClientGrpc) {}\n\n  onModuleInit() {\n    this.paymentService = this.client.getService('PaymentService');\n  }\n\n  async createPayment(data: CreatePaymentRequest) {\n    return firstValueFrom(this.paymentService.CreatePayment(data));\n  }\n\n  async capturePayment(data: { payment_order_id?: string; paypal_order_id?: string }) {\n    return firstValueFrom(this.paymentService.CapturePayment(data));\n  }\n}\n<\/code><\/pre>\n<h3 id=\"heading-domain-service-business-logic-example\">\u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u0628\u0632\u0646\u0633 \u0645\u0646\u0637\u0642 \u06a9\u06cc \u0645\u062b\u0627\u0644:<\/h3>\n<p>\u06cc\u06c1 \u0645\u062b\u0627\u0644 \u062f\u06a9\u06be\u0627\u062a\u06cc \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0627\u06cc\u06a9 \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0633\u0631\u0648\u0633 \u06a9\u0648 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u0633\u0648\u0646\u067e\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0688\u06cc\u0679\u0627 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ application-payment.service.ts\n\nasync initiateTuitionPayment(applicationId: number, options: { domain: string }) {\n  const application = await this.applicationModel.findByPk(applicationId);\n\n  \/\/ Build PayPal return URLs from frontend domain\n  const frontendBase = options.domain; \/\/ e.g. https:\/\/crm.yourapp.com\n  const returnUrl = `${frontendBase}\/payment\/successful?applicationId=${application.applicationId}`;\n  const cancelUrl = `${frontendBase}\/payment\/failure?applicationId=${application.applicationId}`;\n\n  const result = await this.paymentClient.createPayment({\n    checkout_id: `checkout-app-${application.id}`,\n    payment_order_id: uuidv4(),\n    domain: 'application',\n    reference_id: String(application.id),\n    payer_id: application.studentId,\n    amount: finalAmount.toFixed(2),\n    currency: 'USD',\n    buyer_email: buyerEmail,\n    seller_account: `university-${application.universityId}`,\n    payment_category: 'tuition_deposit',\n    return_url: returnUrl,\n    cancel_url: cancelUrl,\n    idempotency_key: `app-${application.id}-tuition-${uuidv4()}`,\n  });\n\n  return {\n    approveUrl: result.approve_url,\n    paypalOrderId: result.paypal_order_id,\n    paymentOrderId: result.payment_order_id,\n  };\n}\n<\/code><\/pre>\n<p>\u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0642\u0648\u0627\u0646\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0630\u0645\u06c1 \u062f\u0627\u0631 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u062e\u0648\u062f \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p><strong>\u0627\u06c1\u0645:<\/strong> \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u0648 \u0627\u067e\u0646\u0627 \u0627\u0635\u0644 \u0627\u0633 \u0637\u0631\u062d \u0628\u06be\u06cc\u062c\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2: <code>domain<\/code> \u0644\u06c1\u0630\u0627 \u0648\u0627\u067e\u0633\u06cc \u06cc\u0648 \u0622\u0631 \u0627\u06cc\u0644 \u062f\u0631\u0633\u062a \u0645\u0627\u062d\u0648\u0644 \u06a9\u06cc \u0637\u0631\u0641 \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 (\u0688\u06cc\u0648 \u067e\u0631 \u0644\u0648\u06a9\u0644 \u06c1\u0648\u0633\u0679\u060c \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u06cc\u0648 \u0622\u0631 \u0627\u06cc\u0644)\u06d4<\/p>\n<h2 id=\"heading-step-6-add-the-api-gateway-layer\">\u0645\u0631\u062d\u0644\u06c1 6 &#8211; API \u06af\u06cc\u0679 \u0648\u06d2 \u067e\u0631\u062a \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>API \u06af\u06cc\u0679 \u0648\u06d2 \u0627\u06cc\u06a9 HTTP \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u06a9\u0648 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u067e\u0631 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u06a9\u0648 \u0622\u06af\u06d2 \u0628\u06be\u06cc\u062c \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">POST \/applications\/:id\/pay\/applicationfee\nBody: { \"domain\": \"https:\/\/crm.yourapp.com\", \"couponCode\": \"SAVE10\" }\n<\/code><\/pre>\n<pre><code class=\"language-typescript\">\/\/ student-apigw \u2192 students-service (gRPC) \u2192 payment-service (gRPC) \u2192 PayPal\n<\/code><\/pre>\n<p>\u06af\u06cc\u0679 \u0648\u06d2 \u06a9\u06cc \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc\u0627\u06ba:<\/p>\n<ul>\n<li>\n<p>\u062a\u0635\u062f\u06cc\u0642 (JWT)<\/p>\n<\/li>\n<li>\n<p>\u062a\u0635\u062f\u06cc\u0642 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a<\/p>\n<\/li>\n<li>\n<p>\u0645\u06cc\u0631\u06d2 \u067e\u0627\u0633 \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06cc \u0627\u0633\u0646\u0627\u062f \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 \u06a9\u06d2 \u0628\u0639\u062f \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06c1 \u067e\u0631 \u0642\u0628\u0636\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">POST \/applications\/:id\/pay\/applicationfee\/capture\nBody: { \"paypalOrderId\": \"PAYPAL_ORDER_ID_FROM_URL\" }\n<\/code><\/pre>\n<h2 id=\"heading-step-7-publish-payment-events-with-rabbitmq\">\u0645\u0631\u062d\u0644\u06c1 7 &#8211; RabbitMQ \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062a\u0642\u0631\u06cc\u0628 \u0634\u0627\u0626\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>RabbitMQ \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u063a\u06cc\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u0645\u0648\u0627\u0635\u0644\u0627\u062a \u06a9\u0648 \u0642\u0627\u0628\u0644 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0628\u0639\u062f \u062a\u0645\u0627\u0645 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0627 \u067e\u0631\u0648\u0633\u06cc\u0633\u0646\u06af \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0633\u0631\u0648\u0633 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0627\u06cc\u0648\u0646\u0679 \u0634\u0627\u0626\u0639 \u06a9\u0631\u062a\u06cc \u06c1\u06d2 \u0627\u0648\u0631 \u062f\u0644\u0686\u0633\u067e\u06cc \u0631\u06a9\u06be\u0646\u06d2 \u0648\u0627\u0644\u06cc \u062e\u062f\u0645\u0627\u062a \u06a9\u0648 \u0622\u0632\u0627\u062f\u0627\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u0627\u0633 \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631\u0646\u06d2 \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06a9\u0627\u0645\u06cc\u0627\u0628 \u06af\u0631\u0641\u062a\u0627\u0631\u06cc \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u06cc\u06a9 \u0648\u0627\u0642\u0639\u06c1 \u0634\u0627\u0626\u0639 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ payment-events.publisher.ts\n\nasync publishCompleted(event: PaymentCompletedEvent) {\n  const pattern = `payment.${event.domain}.completed`; \/\/ e.g. payment.application.completed\n  this.eventsClient.emit(pattern, { ...event, eventId: uuidv4() });\n}\n<\/code><\/pre>\n<p>\u06c1\u0631 \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u0622\u067e \u06a9\u06d2 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0688\u0648\u0645\u06cc\u0646 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0648 \u0633\u0628\u0633\u06a9\u0631\u0627\u0626\u0628 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0637\u0644\u0628\u0627\u0621 \u06a9\u06cc \u062e\u062f\u0645\u0627\u062a \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba: <code>payment.application.completed<\/code> \u0622\u067e \u0637\u0627\u0644\u0628 \u0639\u0644\u0645 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0648 \u06a9\u0633\u06cc \u062a\u0642\u0631\u06cc\u0628 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u062f\u0627 \u0634\u062f\u06c1 \u06a9\u06d2 \u0628\u0637\u0648\u0631 \u0646\u0634\u0627\u0646 \u0632\u062f \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ payment-events.consumer.ts (students-service)\n\n@EventPattern('payment.application.completed')\nasync handlePaymentCompleted(@Payload() data: PaymentCompletedPayload) {\n  await this.applicationPaymentService.handlePaymentCompletedEvent(data);\n  \/\/ Marks application as PAID, records payment history\n}\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0622\u067e \u06a9\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0648 \u0622\u067e \u06a9\u06d2 \u0688\u0648\u0645\u06cc\u0646 \u06a9\u0648 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0627\u0644\u06af \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633\u06c1\u0627\u0644 <code>students-service<\/code> \u0627\u06af\u0631 \u06cc\u06c1 \u0639\u0627\u0631\u0636\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0628\u0646\u062f \u06c1\u06d2\u060c \u062a\u0648 \u0622\u067e \u0642\u0637\u0627\u0631 \u0633\u06d2 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-two-paths-to-mark-an-order-as-paid\">\u0622\u0631\u0688\u0631 \u06a9\u0648 \u0628\u0637\u0648\u0631 \u0627\u062f\u0627 \u0634\u062f\u06c1 \u0646\u0634\u0627\u0646 \u0632\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u062f\u0648 \u0631\u0627\u0633\u062a\u06d2<\/h3>\n<table>\n<thead>\n<tr>\n<th>\u0633\u0691\u06a9<\/th>\n<th>\u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>\u06c1\u0645 \u0648\u0642\u062a \u0633\u0627\u0632 \u06af\u0631\u0641\u062a<\/strong><\/td>\n<td>\u067e\u06d2 \u067e\u0627\u0644 \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 API \u06a9\u06d2 \u0628\u0639\u062f \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u0627\u0644\u0632 \u06a9\u06cc\u067e\u0686\u0631 \u06a9\u0631\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td><strong>\u0645\u062a\u0636\u0627\u062f \u0648\u0627\u0642\u0639\u06c1<\/strong><\/td>\n<td>RabbitMQ \u0635\u0627\u0631\u0641 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0627\u06cc\u0648\u0646\u0679 \u0634\u0627\u0626\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f \u0688\u0648\u0645\u06cc\u0646 \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u062f\u0648\u0646\u0648\u06ba \u06a9\u0648 \u0627\u06cc\u06a9 \u0633\u0627\u062a\u06be \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0627\u0633\u062a\u0642\u0644\u0627\u0644 \u062d\u0627\u0635\u0644 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 Sync Path \u0641\u0648\u0631\u06cc UX \u0641\u06cc\u0688 \u0628\u06cc\u06a9 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u063a\u06cc\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u0631\u0627\u0633\u062a\u06d2 \u0627\u06cc\u06a9 \u062d\u0641\u0627\u0638\u062a\u06cc \u062c\u0627\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-step-8-database-schema-and-migrations\">\u0645\u0631\u062d\u0644\u06c1 8 &#8211; \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0627\u0633\u06a9\u06cc\u0645\u0627 \u0627\u0648\u0631 \u06c1\u062c\u0631\u062a<\/h2>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0627\u067e\u0646\u0627 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0627\u0633\u06a9\u06cc\u0645\u0627 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06d2\u06d4 \u06c1\u0631 \u0679\u06cc\u0628\u0644 \u06a9\u06cc \u0645\u062e\u0635\u0648\u0635 \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc\u0627\u06ba \u06c1\u0648\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0646\u0627 \u06a9\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688\u060c \u0645\u0627\u0644\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646\u060c \u0627\u0648\u0631 \u0648\u06cc\u0628 \u06c1\u06a9 \u067e\u0631\u0648\u0633\u06cc\u0633\u0646\u06af \u062f\u06cc\u06af\u0631 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u062e\u062f\u0645\u0627\u062a \u0633\u06d2 \u0627\u0644\u06af \u062a\u06be\u0644\u06af \u0631\u06c1\u06cc\u06ba\u06d4<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0645\u06cc\u0632<\/th>\n<th>\u0645\u0642\u0635\u062f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>payment_events<\/code><\/td>\n<td>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0627 \u0633\u06cc\u0634\u0646 (\u062e\u0631\u06cc\u062f\u0627\u0631\/\u0628\u06cc\u0686\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06a9\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a)<\/td>\n<\/tr>\n<tr>\n<td><code>payment_orders<\/code><\/td>\n<td>PayPal ID \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0627\u0646\u0641\u0631\u0627\u062f\u06cc \u06a9\u0648\u0634\u0634<\/td>\n<\/tr>\n<tr>\n<td><code>ledger_entries<\/code><\/td>\n<td>\u0641\u0646\u0627\u0646\u0634\u0644 \u0622\u0688\u0679 \u0679\u0631\u06cc\u0644<\/td>\n<\/tr>\n<tr>\n<td><code>wallets<\/code><\/td>\n<td>\u0628\u06cc\u0686\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0628\u06cc\u0644\u0646\u0633 \u0633\u06d2 \u0628\u0627\u062e\u0628\u0631 \u0631\u06c1\u0646\u0627<\/td>\n<\/tr>\n<tr>\n<td><code>processed_webhooks<\/code><\/td>\n<td>\u0648\u06cc\u0628 \u06c1\u064f\u06a9 \u0688\u06cc\u067e\u0644\u06cc\u06a9\u06cc\u0634\u0646<\/td>\n<\/tr>\n<tr>\n<td><code>coupons<\/code>    \/ <code>coupon_redemptions<\/code><\/td>\n<td>\u0688\u0633\u06a9\u0627\u0624\u0646\u0679 \u06a9\u0648\u0688 (\u0627\u062e\u062a\u06cc\u0627\u0631\u06cc)<\/td>\n<\/tr>\n<tr>\n<td><code>sequelize_meta<\/code><\/td>\n<td>\u0645\u0627\u0626\u06cc\u06af\u0631\u06cc\u0634\u0646 \u0679\u0631\u06cc\u06a9\u0646\u06af<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 id=\"heading-production-migration-gotcha\">\u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06cc \u0645\u0646\u062a\u0642\u0644\u06cc \u06a9\u06d2 \u0645\u0633\u0627\u0626\u0644<\/h3>\n<p>\u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0688\u0648\u06a9\u0631 \u0627\u0645\u06cc\u062c \u0633\u06d2 \u06c1\u062c\u0631\u062a \u06a9\u0631\u06cc\u06ba\u06d4 <code>.ts<\/code> \u0641\u0627\u0626\u0644 \u06c1\u06d2\u06d4 <strong>~ \u0646\u06c1\u06cc\u06ba<\/strong> \u0622\u067e \u0627\u0633\u06d2 \u0627\u0633 \u0648\u0642\u062a \u062a\u06a9 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0628 \u062a\u06a9 \u06a9\u06c1 \u0622\u067e \u0627\u0633\u06d2 \u062c\u0627\u0648\u0627 \u0627\u0633\u06a9\u0631\u067e\u0679 \u067e\u0631 \u0645\u0631\u062a\u0628 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633\u06d2 \u062a\u0635\u0648\u06cc\u0631 \u0645\u06cc\u06ba \u06a9\u0627\u067e\u06cc \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-dockerfile\"># Dockerfile \u2014 compile migrations for production\nRUN pnpm exec tsc --project apps\/core\/payment-service\/tsconfig.migrations.json\nCOPY --from=builder \/app\/dist\/apps\/core\/payment-service\/migrations .\/migrations\n<\/code><\/pre>\n<p>\u0627\u06af\u0631 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u06cc\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u062a\u0648 \u0622\u067e \u0627\u0633\u06d2 \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>Executed 0 migrations<\/code> \u0644\u0627\u06af \u0627\u0648\u0631 <strong>\u0679\u06cc\u0628\u0644 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/strong>.<\/p>\n<p>\u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-sql\">CREATE USER payment_user WITH PASSWORD 'payment_pass';\nCREATE DATABASE payment_db;\nGRANT ALL PRIVILEGES ON DATABASE payment_db TO payment_user;\n<\/code><\/pre>\n<h2 id=\"heading-step-9-local-development-setup-docker\">\u0645\u0631\u062d\u0644\u06c1 9 &#8211; \u0645\u0642\u0627\u0645\u06cc \u062a\u0631\u0642\u06cc \u0642\u0627\u0626\u0645 \u06a9\u0631\u06cc\u06ba (\u0688\u0648\u06a9\u0631)<\/h2>\n<h3 id=\"heading-environment-variables-env\">\u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a (<code>.env<\/code>)<\/h3>\n<pre><code class=\"language-bash\">PAYPAL_CLIENT_ID=your_sandbox_client_id\nPAYPAL_CLIENT_SECRET=your_sandbox_client_secret\nPAYPAL_API_BASE=https:\/\/api-m.sandbox.paypal.com\n<\/code><\/pre>\n<p>\u0627\u0633 \u0633\u06cc\u06a9\u0634\u0646 \u0645\u06cc\u06ba\u060c \u0622\u067e \u0688\u0648\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0645\u0642\u0627\u0645\u06cc \u062a\u0631\u0642\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0633\u0631\u0648\u0633 \u062a\u0634\u06a9\u06cc\u0644 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0633\u06cc\u0679 \u0627\u067e \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc\u0648\u06ba \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0628\u06c1\u062a\u0631\u06cc\u0646 \u0645\u0627\u062d\u0648\u0644 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-docker-compose-local\">\u0688\u0627\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632 (\u0645\u0642\u0627\u0645\u06cc)<\/h3>\n<p>\u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0646\u0641\u06cc\u06af\u0631\u06cc\u0634\u0646 \u067e\u0648\u0633\u0679\u06af\u0631\u06cc \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644 \u0627\u0648\u0631 \u0631\u06cc\u0628\u0679 \u0627\u06cc\u0645 \u06a9\u06cc\u0648 \u0633\u0645\u06cc\u062a \u0645\u0637\u0644\u0648\u0628\u06c1 \u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-yaml\">payment-service:\n  build:\n    dockerfile: apps\/core\/payment-service\/Dockerfile.dev\n  ports:\n    - '3003:3003'    # HTTP\n    - '50061:50061'  # gRPC\n  environment:\n    - PAYPAL_API_BASE=https:\/\/api-m.sandbox.paypal.com\n    - PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}\n    - PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}\n    - DB_HOST=postgres\n    - DB_NAME=payment_db\n    - DB_USER=payment_user\n    - DB_PASSWORD=payment_pass\n    - RABBITMQ_URL=amqp:\/\/rabbitmq:5672\n\nstudents-service:\n  environment:\n    - PAYMENT_SERVICE_URL=payment-service:50061\n  depends_on:\n    payment-service:\n      condition: service_healthy\n<\/code><\/pre>\n<h3 id=\"heading-start-services\">\u0633\u0631\u0648\u0633 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u06a9\u0646\u0641\u06cc\u06af\u0631\u06cc\u0634\u0646 \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u06a9\u0646\u0679\u06cc\u0646\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0628\u06c1\u0627\u0624 \u06a9\u0648 \u062c\u0627\u0646\u0686\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba \u06a9\u06c1 \u062a\u0645\u0627\u0645 \u0633\u0631\u0648\u0633\u0632 \u0635\u062d\u06cc\u062d \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0686\u0644 \u0631\u06c1\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">docker compose up -d payment-service students-service student-apigw\n<\/code><\/pre>\n<h3 id=\"heading-verify-health\">\u0627\u0633\u0679\u06cc\u0679\u0633 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:3003\/health\n# {\"status\":\"healthy\",\"service\":\"payment-service\",...}\n<\/code><\/pre>\n<h3 id=\"heading-test-payment-flow\">\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0628\u06c1\u0627\u0624 \u06a9\u06cc \u062c\u0627\u0646\u0686<\/h3>\n<ol>\n<li>\n<p>\u06a9\u0627\u0644 <code>POST \/applications\/:id\/pay\/applicationfee<\/code> \u06a9\u06d2 \u0633\u0627\u062a\u06be <code>{ \"domain\": \"http:\/\/localhost:3000\" }<\/code><\/p>\n<\/li>\n<li>\n<p>\u0644\u0648\u0679\u0627 \u06c1\u0648\u0627 \u0645\u0648\u0627\u062f \u06a9\u06be\u0648\u0644\u06cc\u06ba\u06d4 <code>approveUrl<\/code> \u0622\u067e \u06a9\u06d2 \u0628\u0631\u0627\u0624\u0632\u0631 \u0645\u06cc\u06ba<\/p>\n<\/li>\n<li>\n<p>\u0627\u067e\u0646\u06d2 \u067e\u06d2 \u067e\u0627\u0644 \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u062e\u0631\u06cc\u062f\u0627\u0631 \u0627\u06a9\u0627\u0624\u0646\u0679 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0645\u0646\u0638\u0648\u0631\u06cc \u06a9\u06d2 \u0628\u0639\u062f \u0645\u062c\u06be\u06d2 \u06a9\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>POST \/applications\/:id\/pay\/applicationfee\/capture<\/code> \u06a9\u06d2 \u0633\u0627\u062a\u06be <code>paypalOrderId<\/code><\/p>\n<\/li>\n<li>\n<p>\u0627\u067e\u0646\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 <code>PAID<\/code><\/p>\n<\/li>\n<\/ol>\n<h2 id=\"heading-step-10-production-deployment\">\u0645\u0631\u062d\u0644\u06c1 10 &#8211; \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06cc \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc\u06d4<\/h2>\n<p>\u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0627\u06af\u0644\u0627 \u0645\u0631\u062d\u0644\u06c1 \u067e\u06cc\u0645\u0646\u0679 \u0633\u0631\u0648\u0633 \u06a9\u0648 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0641\u0631\u0642 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u067e\u06d2 \u067e\u0627\u0644 \u0644\u0627\u0626\u06cc\u0648 \u0627\u0633\u0646\u0627\u062f\u060c \u067e\u06cc\u062f\u0627\u0648\u0627\u0631\u06cc \u0645\u0627\u062d\u0648\u0644 \u06a9\u06d2 \u0645\u062a\u063a\u06cc\u0631\u0627\u062a\u060c \u0627\u0648\u0631 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u0688\u0627\u06a9\u0631 \u0627\u0645\u06cc\u062c \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-paypal-live-credentials\">\u067e\u06d2 \u067e\u0627\u0644 \u0644\u0627\u0626\u06cc\u0648 \u0627\u0633\u0646\u0627\u062f<\/h3>\n<ol>\n<li>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u0688\u06cc\u0648\u0644\u067e\u0631 \u0688\u06cc\u0634 \u0628\u0648\u0631\u0688 \u2192 \u0644\u0627\u0626\u06cc\u0648 \u0627\u06cc\u067e \u067e\u0631 \u062c\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0627\u06cc\u06a9 \u0644\u0627\u0626\u06cc\u0648 REST API \u0627\u06cc\u067e \u0628\u0646\u0627\u0626\u06cc\u06ba<\/p>\n<\/li>\n<li>\n<p>\u06a9\u0644\u0627\u0626\u0646\u0679 \u0622\u0626\u06cc \u0688\u06cc \u0627\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u0627\u067e\u06cc \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ol>\n<h3 id=\"heading-production-env-on-server-never-commit\">\u067e\u06cc\u062f\u0627\u0648\u0627\u0631 <code>.env<\/code> (\u0633\u0631\u0648\u0631 \u067e\u0631 &#8211; \u06a9\u0648\u0626\u06cc \u0639\u06c1\u062f \u0646\u06c1\u06cc\u06ba)<\/h3>\n<pre><code class=\"language-bash\">PAYPAL_CLIENT_ID=your_live_client_id\nPAYPAL_CLIENT_SECRET=your_live_secret\nPAYPAL_API_BASE=https:\/\/api-m.paypal.com\n<\/code><\/pre>\n<h3 id=\"heading-docker-compose-production\">\u0688\u0627\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632 (\u067e\u0631\u0648\u0688\u06a9\u0634\u0646)<\/h3>\n<pre><code class=\"language-yaml\">payment-service:\n  build:\n    dockerfile: apps\/core\/payment-service\/Dockerfile\n  environment:\n    - NODE_ENV=production\n    - PAYPAL_API_BASE=${PAYPAL_API_BASE:-https:\/\/api-m.paypal.com}\n    - PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}\n    - PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}\n    - DB_HOST=${DB_HOST}\n    - DB_NAME=payment_db\n    - DB_USER=payment_user\n    - DB_PASSWORD=payment_pass\n    - RABBITMQ_URL=amqp:\/\/${RABBITMQ_USER}:${RABBITMQ_PASS}@rabbitmq:5672\n  labels:\n    - 'traefik.http.routers.payment.rule=Host(`payment-service.yourapp.com`)'\n\nstudents-service:\n  environment:\n    - PAYMENT_SERVICE_URL=payment-service:50061\n  depends_on:\n    payment-service:\n      condition: service_healthy\n<\/code><\/pre>\n<h3 id=\"heading-deploy-commands\">\u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u0627 \u062d\u06a9\u0645<\/h3>\n<pre><code class=\"language-bash\">docker compose -f docker-compose.prod.yml build --no-cache payment-service\ndocker compose -f docker-compose.prod.yml up -d payment-service students-service\n<\/code><\/pre>\n<h3 id=\"heading-verify-production\">\u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642<\/h3>\n<pre><code class=\"language-bash\">curl https:\/\/payment-service.yourapp.com\/health\n\ndocker logs -f apply-goal-payment-service\n# Look for:\n#   environment: live\n#   Found 8 pending migrations\n#   Executed 8 migrations\n<\/code><\/pre>\n<h3 id=\"heading-frontend-domain-in-production\">\u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u0645\u06cc\u06ba \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0688\u0648\u0645\u06cc\u0646<\/h3>\n<p>\u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u0648 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 CRM URL \u0628\u06be\u06cc\u062c\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<pre><code class=\"language-json\">{ \"domain\": \"https:\/\/crm.yourapp.com\" }\n<\/code><\/pre>\n<p>\u0646\u06c1\u06cc\u06ba <code>localhost<\/code>. \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0628\u0639\u062f \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u0648 \u06a9\u06c1\u0627\u06ba \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-step-11-health-checks-and-monitoring\">\u0645\u0631\u062d\u0644\u06c1 11 &#8211; \u062d\u0627\u0644\u062a \u06a9\u06cc \u062c\u0627\u0646\u0686 \u0627\u0648\u0631 \u0646\u06af\u0631\u0627\u0646\u06cc \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u06c1\u06cc\u0644\u062a\u06be \u0686\u06cc\u06a9 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u0679\u0648\u0644\u0632 \u062c\u06cc\u0633\u06d2 Docker \u0627\u0648\u0631 Traefik \u06a9\u0648 \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0622\u067e \u06a9\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0633\u0631\u0648\u0633 \u0635\u062d\u06cc\u062d \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0686\u0644 \u0631\u06c1\u06cc \u06c1\u06d2\u06d4 \u0627\u0646 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u06a9\u0627\u062a \u06a9\u06cc \u0646\u06af\u0631\u0627\u0646\u06cc \u0633\u06d2 \u063a\u0644\u0637\u06cc\u0648\u06ba \u06a9\u0627 \u062c\u0644\u062f \u067e\u062a\u06c1 \u0644\u06af\u0627\u0646\u06d2 \u0627\u0648\u0631 \u0627\u06cc\u067e\u0644\u06cc\u06a9\u06cc\u0634\u0646 \u06a9\u06cc \u0628\u06be\u0631\u0648\u0633\u06d2 \u06a9\u0648 \u0628\u06c1\u062a\u0631 \u0628\u0646\u0627\u0646\u06d2 \u0645\u06cc\u06ba \u0645\u062f\u062f \u0645\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ GET \/health\n{ \"status\": \"healthy\", \"service\": \"payment-service\", \"timestamp\": \"...\", \"version\": \"1.0.0\" }\n<\/code><\/pre>\n<p>\u06a9\u06c1\u0627\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u0627 \u06c1\u06d2:<\/p>\n<ul>\n<li>\n<p>\u0688\u0627\u06a9\u0631 <code>HEALTHCHECK<\/code><\/p>\n<\/li>\n<li>\n<p>\u0679\u0631\u06cc\u0641\u06a9 \u0644\u0648\u0688 \u0628\u06cc\u0644\u0646\u0633\u0631<\/p>\n<\/li>\n<li>\n<p>\u0627\u067e \u0679\u0627\u0626\u0645 \u0646\u06af\u0631\u0627\u0646\u06cc<\/p>\n<\/li>\n<\/ul>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u06a9\u06cc \u0627\u0633\u0646\u0627\u062f \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u0622\u063a\u0627\u0632 \u067e\u0631 \u0686\u0644\u0627\u0626\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u0628\u0630\u0631\u06cc\u0639\u06c1: <code>PayPalService.logConfiguration()<\/code>.<\/p>\n<h2 id=\"heading-complete-request-flow-real-example\">\u0645\u06a9\u0645\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0627 \u0628\u06c1\u0627\u0624 (\u062d\u0642\u06cc\u0642\u06cc \u062f\u0646\u06cc\u0627 \u06a9\u06cc \u0645\u062b\u0627\u0644)<\/h2>\n<p><strong>\u0633\u06a9\u0631\u067e\u0679:<\/strong> \u0637\u0644\u0628\u0627\u0621 \u06a9\u0627\u0644\u062c \u0645\u06cc\u06ba \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0679\u06cc\u0648\u0634\u0646 \u0627\u062f\u0627 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">1. Frontend\n   POST \/applications\/42\/pay\/applicationfee\n   Body: { \"domain\": \"https:\/\/crm.yourapp.com\" }\n        \u2502\n        \u25bc\n2. student-apigw (HTTP \u2192 gRPC)\n   InitiateApplicationTuitionPayment(applicationId: 42)\n        \u2502\n        \u25bc\n3. students-service\n   - Validates application not already paid\n   - Resolves tuition amount\n   - Optionally validates coupon via payment-service gRPC\n   - Builds returnUrl \/ cancelUrl from domain\n   - Calls payment-service CreatePayment (gRPC)\n        \u2502\n        \u25bc\n4. payment-service\n   - Creates payment_orders record (EXECUTING)\n   - Calls PayPal POST \/v2\/checkout\/orders\n   - Returns approveUrl\n        \u2502\n        \u25bc\n5. Frontend redirects user to approveUrl (PayPal checkout)\n        \u2502\n        \u25bc\n6. User approves \u2192 PayPal redirects to returnUrl\n        \u2502\n        \u25bc\n7. Frontend\n   POST \/applications\/42\/pay\/applicationfee\/capture\n   Body: { \"paypalOrderId\": \"PAYPAL_ORDER_ID\" }\n        \u2502\n        \u25bc\n8. payment-service\n   - POST \/v2\/checkout\/orders\/{id}\/capture\n   - Updates order \u2192 SUCCESS\n   - Updates wallet + ledger\n   - Publishes payment.application.completed \u2192 RabbitMQ\n        \u2502\n        \u25bc\n9. students-service (event consumer)\n   - Marks application paymentStatus = PAID\n   - Records payment in application_payments table\n<\/code><\/pre>\n<h2 id=\"heading-coupon-support-optional\">\u06a9\u0648\u067e\u0646 \u0633\u067e\u0648\u0631\u0679 (\u0627\u062e\u062a\u06cc\u0627\u0631\u06cc)<\/h2>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u0622\u0631\u0688\u0631 \u0628\u0646\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u06a9\u0648\u067e\u0646 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">const validation = await this.paymentClient.validateCoupon({\n  code: 'SAVE20',\n  universityId: application.universityId,\n  originalAmount: 500,\n  paymentType: 'application_fee',\n});\n\nconst finalAmount = validation.data.finalAmount;\n\n\/\/ If coupon covers 100% \u2014 skip PayPal entirely\nif (finalAmount <= 0) {\n  await this.markApplicationPaid(applicationId, { amount: 0, source: 'coupon' });\n  return { paymentOrderStatus: 'COMPLETED' };\n}\n<\/code><\/pre>\n<p>\u06a9\u0648\u067e\u0646 \u0645\u0646\u0637\u0642 \u0632\u0646\u062f\u06c1 \u0627\u0648\u0631 \u0627\u0686\u06be\u06cc \u06c1\u06d2\u06d4 <code>payment-service<\/code> \u0627\u0633 \u0644\u06cc\u06d2 \u0631\u0639\u0627\u06cc\u062a \u06a9\u06d2 \u0642\u0648\u0627\u0646\u06cc\u0646 \u0645\u0631\u06a9\u0632\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-paypal-webhooks-optional-but-recommended\">\u067e\u06d2 \u067e\u0627\u0644 \u0648\u06cc\u0628 \u06c1\u06a9 (\u0627\u062e\u062a\u06cc\u0627\u0631\u06cc\u060c \u0644\u06cc\u06a9\u0646 \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062f\u06c1)<\/h2>\n<p>\u0627\u067e\u0646\u06d2 \u067e\u06d2 \u067e\u0627\u0644 \u0688\u06cc\u0634 \u0628\u0648\u0631\u0688 \u0645\u06cc\u06ba \u0648\u06cc\u0628 \u06c1\u06a9 URL \u06a9\u0648 \u0631\u062c\u0633\u0679\u0631 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">https:\/\/payment-service.yourapp.com\/api\/v1\/payments\/webhooks\/paypal\n<\/code><\/pre>\n<p>\u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2:<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0648\u0627\u0642\u0639\u06c1<\/th>\n<th>\u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>CHECKOUT.ORDER.APPROVED<\/code><\/td>\n<td>\u0622\u0631\u0688\u0631\u0632 \u06a9\u06cc \u062e\u0648\u062f\u06a9\u0627\u0631 \u06af\u0631\u0641\u062a\u0627\u0631\u06cc\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>PAYMENT.CAPTURE.COMPLETED<\/code><\/td>\n<td>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0645\u06a9\u0645\u0644 \u06a9\u0631\u06cc\u06ba \u0627\u06af\u0631 \u0622\u067e \u0646\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u0627\u06cc\u0633\u0627 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u0648\u06cc\u0628 \u06c1\u06a9 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u06cc \u0646\u0642\u0644 \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u0628\u0630\u0631\u06cc\u0639\u06c1: <code>processed_webhooks<\/code> \u06cc\u06c1 \u0645\u06cc\u0632 \u0688\u0628\u0644 \u067e\u0631\u0648\u0633\u06cc\u0633\u0646\u06af \u06a9\u0648 \u0631\u0648\u06a9\u0646\u06d2 \u06a9\u06d2 \u0644\u0626\u06d2 \u06c1\u06d2.<\/p>\n<h2 id=\"heading-testing-checklist\">\u062c\u0627\u0646\u0686 \u067e\u0691\u062a\u0627\u0644 \u06a9\u06cc \u0641\u06c1\u0631\u0633\u062a<\/h2>\n<ul>\n<li>\n<p>[ ] <code>GET \/health<\/code>    200 \u0644\u0648\u0679\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>[ ]    \u067e\u06d2 \u067e\u0627\u0644 \u0644\u0627\u06af\u0632 \u062f\u06a9\u06be\u0627\u0626\u06cc\u06ba\u06d4 <code>credentialsPresent: true<\/code><\/p>\n<\/li>\n<li>\n<p>[ ]    \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0679\u06cc\u0628\u0644 \u0627\u0633\u0679\u0627\u0631\u0679 \u0627\u067e \u06a9\u06d2 \u0628\u0639\u062f \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2 (<code>payment_orders<\/code>, <code>payment_events<\/code>\u0648\u063a\u06cc\u0631\u06c1)<\/p>\n<\/li>\n<li>\n<p>[ ]    \u0627\u06cc\u06a9 \u062f\u0631\u0633\u062a \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0648\u0627\u067e\u0633\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba <code>approveUrl<\/code><\/p>\n<\/li>\n<li>\n<p>[ ]    \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u06a9\u06d2 \u062e\u0631\u06cc\u062f\u0627\u0631 \u0627\u067e\u0646\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u0645\u06a9\u0645\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>[ ]    \u0648\u0627\u067e\u0633\u06cc \u06a9\u06cc\u067e\u0686\u0631 <code>payment_order_status: SUCCESS<\/code><\/p>\n<\/li>\n<li>\n<p>[ ]    \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u0628\u0637\u0648\u0631 \u0646\u0634\u0627\u0646 \u0632\u062f \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 <code>PAID<\/code> \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u0645\u06cc\u06ba<\/p>\n<\/li>\n<li>\n<p>[ ]    RabbitMQ \u0648\u0627\u0642\u0639\u0627\u062a <code>payment.application.completed<\/code> \u06a9\u06be\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2<\/p>\n<\/li>\n<li>\n<p>[ ]    \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u06a9\u06cc\u067e\u0686\u0631 \u06a9\u0648 \u062e\u0648\u0628\u0635\u0648\u0631\u062a\u06cc \u0633\u06d2 \u0633\u0646\u0628\u06be\u0627\u0644\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 (\u0622\u062f\u0645\u06cc)\u06d4<\/p>\n<\/li>\n<li>\n<p>[ ]    \u06a9\u0648\u067e\u0646 100% \u0688\u0633\u06a9\u0627\u0624\u0646\u0679 \u067e\u06d2 \u067e\u0627\u0644 \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>[ ]    \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 <code>https:\/\/api-m.paypal.com<\/code> (\u0644\u0627\u0626\u06cc\u0648)<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"heading-wrapping-up\">\u062e\u062a\u0645<\/h2>\n<p>\u067e\u06d2 \u067e\u0627\u0644 \u06a9\u0648 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u0645\u06cc\u06ba \u0636\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u06a9\u0626\u06cc \u0627\u0635\u0648\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<ol>\n<li>\n<p>\u0627\u06cc\u06a9 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u062a\u0645\u0627\u0645 PayPal API \u06a9\u0627\u0644\u0648\u06ba \u06a9\u06cc \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>gRPC \u0622\u067e \u06a9\u06cc \u0688\u0648\u0645\u06cc\u0646 \u0633\u0631\u0648\u0633 \u06a9\u0648 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0622\u067e \u06a9\u06cc \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0633\u06d2 \u062c\u0648\u0691\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>RabbitMQ \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0646\u0634\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0688\u0648\u0645\u06cc\u0646 \u06a9\u06cc \u062e\u062f\u0645\u0627\u062a \u0688\u06cc \u062c\u0648\u067e\u0644 \u0631\u06c1\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u063a\u06cc\u0631\u0645\u0639\u0645\u0648\u0644\u06cc \u0686\u0627\u0628\u06cc\u0627\u06ba \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0628\u0644\u0646\u06af \u0633\u06d2 \u06af\u0631\u06cc\u0632 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633 \u0627\u0648\u0631 \u0644\u0627\u0626\u06cc\u0648 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0679\u0648\u06af\u0644 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba \u2014 \u06a9\u0648\u0688 \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0622\u067e \u06a9\u0648 \u0627\u067e\u0646\u06cc \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0688\u0648\u06a9\u0631 \u0627\u0645\u06cc\u062c \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u067e\u0646\u06cc \u0645\u0646\u062a\u0642\u0644\u06cc \u06a9\u0648 \u0645\u0631\u062a\u0628 \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06af\u0627\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0633\u0627\u0645\u0646\u06d2 \u06a9\u06d2 \u0622\u062e\u0631 \u0645\u06cc\u06ba \u0646\u0642\u0644 \u0648 \u062d\u0645\u0644 <code>domain<\/code> \u0644\u06c1\u0630\u0627 \u0648\u0627\u067e\u0633\u06cc \u06a9\u0627 URL \u062a\u0645\u0627\u0645 \u0645\u0627\u062d\u0648\u0644 \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<\/li>\n<\/ol>\n<p>\u0627\u0633 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u0648 \u0648\u0633\u0639\u062a \u062f\u06cc \u06af\u0626\u06cc \u06c1\u06d2\u06d4 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u0627 \u0627\u06cc\u06a9 \u0645\u062e\u062a\u0644\u0641 \u0637\u0631\u06cc\u0642\u06c1 \u0628\u06be\u06cc\u062c \u06a9\u0631 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0646\u0626\u06cc \u0642\u0633\u0645 (\u0633\u0628\u0633\u06a9\u0631\u067e\u0634\u0646\u060c \u0627\u06cc\u062c\u0646\u0633\u06cc \u0641\u06cc\u0633\u060c \u06cc\u0648\u0646\u06cc\u0648\u0631\u0633\u0679\u06cc \u0633\u0631\u0648\u0633 \u0641\u06cc\u0633) \u200b\u200b\u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>domain<\/code> \u0627\u0648\u0631 <code>payment_category<\/code> - \u067e\u06d2 \u067e\u0627\u0644 \u0627\u0646\u0679\u06cc\u06af\u0631\u06cc\u0634\u0646 \u06a9\u0648\u0688 \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u0626\u06cc \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-further-reading\">\u0627\u0636\u0627\u0641\u06cc \u0648\u0633\u0627\u0626\u0644<\/h2>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u0622\u067e NestJS \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u067e\u06d2 \u067e\u0627\u0644 \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u062e\u062f\u0645\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4 \u0631\u0627\u0633\u062a\u06d2 \u0645\u06cc\u06ba\u060c \u0622\u067e \u0633\u06cc\u06a9\u06be\u06cc\u06ba \u06af\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0627\u062f\u0627\u0626\u06cc\u06af\u06cc \u06a9\u06cc \u0645\u0646\u0637\u0642 \u06a9\u0648 \u0627\u0633 \u06a9\u06cc \u0627\u067e\u0646\u06cc \u0633\u0631\u0648\u0633 \u0645\u06cc\u06ba \u0627\u0644\u06af \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u060c gRPC \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u0646\u0627\u060c RabbitMQ \u06a9\u06d2 [&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-26851","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/26851","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=26851"}],"version-history":[{"count":0,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/26851\/revisions"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/media?parent=26851"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/categories?post=26851"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/tags?post=26851"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}