{"id":24806,"date":"2026-06-02T15:43:37","date_gmt":"2026-06-02T15:43:37","guid":{"rendered":"https:\/\/umang.pk\/2026\/06\/02\/%d9%81%d9%84%d9%b9%d8%b1-%d8%b3%db%92-%d8%a8%db%8c%da%a9-%d8%a7%db%8c%d9%86%da%88-%d8%aa%da%a9-%da%88%d8%a7%d8%b1%d9%b9-%d8%a7%d9%88%d8%b1-%d8%b4%db%8c%d9%84%d9%81-%da%a9%db%92-%d8%b3%d8%a7%d8%aa\/"},"modified":"2026-06-02T15:43:37","modified_gmt":"2026-06-02T15:43:37","slug":"%d9%81%d9%84%d9%b9%d8%b1-%d8%b3%db%92-%d8%a8%db%8c%da%a9-%d8%a7%db%8c%d9%86%da%88-%d8%aa%da%a9-%da%88%d8%a7%d8%b1%d9%b9-%d8%a7%d9%88%d8%b1-%d8%b4%db%8c%d9%84%d9%81-%da%a9%db%92-%d8%b3%d8%a7%d8%aa","status":"publish","type":"post","link":"https:\/\/umang.pk\/en_us\/2026\/06\/02\/%d9%81%d9%84%d9%b9%d8%b1-%d8%b3%db%92-%d8%a8%db%8c%da%a9-%d8%a7%db%8c%d9%86%da%88-%d8%aa%da%a9-%da%88%d8%a7%d8%b1%d9%b9-%d8%a7%d9%88%d8%b1-%d8%b4%db%8c%d9%84%d9%81-%da%a9%db%92-%d8%b3%d8%a7%d8%aa\/","title":{"rendered":"\u0641\u0644\u0679\u0631 \u0633\u06d2 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u062a\u06a9: \u0688\u0627\u0631\u0679 \u0627\u0648\u0631 \u0634\u06cc\u0644\u0641 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 REST API \u0628\u0646\u0627\u0646\u06d2 \u0627\u0648\u0631 \u062c\u0627\u0631\u06cc \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0637\u0631\u06cc\u0642\u06c1"},"content":{"rendered":"\n<div id=\"\">\n<p>\u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0622\u067e \u0688\u0627\u0631\u0679 \u06a9\u0648 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 async\/\u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0648 \u0633\u0645\u062c\u06be\u06cc\u06ba\u060c \u0645\u0627\u0688\u0644\u0632 \u0627\u0648\u0631 \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645 \u06a9\u0631\u06cc\u06ba\u060c \u0635\u0627\u0641 \u0622\u0631\u06a9\u06cc\u0679\u06cc\u06a9\u0686\u0631\u0632 \u0645\u06cc\u06ba \u0633\u0648\u0686\u06cc\u06ba\u060c \u0627\u0648\u0631 \u062d\u0642\u06cc\u0642\u06cc \u0627\u06cc\u067e\u0644\u06cc \u06a9\u06cc\u0634\u0646\u0632 \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4<\/p>\n<p>\u0622\u067e \u0622\u062c \u06a9\u06c1\u0627\u06ba \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062c\u06c1\u0627\u06ba \u0622\u067e \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u0627\u0648\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0633 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0641\u0631\u0642 \u0622\u067e \u06a9\u06d2 \u062e\u06cc\u0627\u0644 \u0633\u06d2 \u06a9\u0645 \u06c1\u06d2\u06d4<\/p>\n<p>\u062c\u0648 \u063a\u0627\u0626\u0628 \u06c1\u06d2 \u0648\u06c1 \u0646\u0626\u06cc \u0632\u0628\u0627\u0646 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06cc\u06c1 \u06a9\u0648\u0626\u06cc \u0646\u06cc\u0627 \u0646\u0645\u0648\u0646\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0633\u0645\u062c\u06be\u0646\u0627 \u06a9\u06c1 \u0688\u0627\u0631\u0679 \u0648\u06cc\u062c\u06cc\u0679 \u0679\u0631\u06cc\u060c BuildContext\u060c \u06cc\u0627 Flutter \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u06a9\u06cc\u0633\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0633 \u0627\u06cc\u06a9 \u0686\u0644 \u0631\u06c1\u0627 \u0639\u0645\u0644 \u06c1\u06d2 \u062c\u0648 HTTP \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06a9\u0644\u0627\u0626\u0646\u0679 \u06a9\u0648 \u062c\u0648\u0627\u0628\u0627\u062a \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0645\u0636\u0645\u0648\u0646 \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u0634\u0631\u0648\u0639 \u0633\u06d2 \u0645\u06a9\u0645\u0644 \u0635\u0627\u0631\u0641 \u0627\u0648\u0631 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0645\u06cc\u0646\u062c\u0645\u0646\u0679 REST API \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 Dart \u0627\u0648\u0631 Shelf \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u060c Docker \u067e\u0631 \u0686\u0644\u0646\u06d2 \u0648\u0627\u0644\u06d2 PostgreSQL \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0633\u06d2 \u062c\u0691\u06cc\u06ba \u06af\u06d2\u060c JWT \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u060c \u0627\u0648\u0631 Fly.io \u067e\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u0622\u062e\u0631 \u0645\u06cc\u06ba\u060c \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u06a9\u0627\u0645 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0627\u060c \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u06af\u0631\u06cc\u0688 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u0688\u0627\u0631\u0679 \u0645\u06cc\u06ba \u0644\u06a9\u06be\u0627 \u06c1\u0648\u0627 \u06c1\u0648\u06af\u0627\u060c \u0648\u06c1\u06cc \u0632\u0628\u0627\u0646 \u062c\u0648 \u0622\u067e \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u0645\u0636\u0645\u0648\u0646 \u062a\u06cc\u0646 \u0645\u062e\u062a\u0644\u0641 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u06cc\u06a9 \u06c1\u06cc \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0633\u06cc\u0631\u06cc\u0632 (\u0627\u0633\u0679\u06cc\u0646\u0688 \u0627\u06a9\u06cc\u0644\u06d2 \u0645\u0636\u0627\u0645\u06cc\u0646) \u06a9\u0627 \u062d\u0635\u06c1 \u06c1\u06d2\u06d4 \u06c1\u0645 \u06cc\u06c1\u0627\u06ba \u0634\u06cc\u0644\u0641\u060c \u0627\u06af\u0644\u06d2 \u0645\u0636\u0645\u0648\u0646 \u0645\u06cc\u06ba Serverpod\u060c \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u0622\u0631\u0679\u06cc\u06a9\u0644 \u0645\u06cc\u06ba Dart Frog \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4 \u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0645\u0648\u0627\u0632\u0646\u06c1 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06c1\u0631 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0627\u06cc\u06a9 \u06c1\u06cc \u0645\u0633\u0626\u0644\u06d2 \u062a\u06a9 \u06a9\u06cc\u0633\u06d2 \u067e\u06c1\u0646\u0686\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-table-of-contents\">\u0627\u0646\u0688\u06cc\u06a9\u0633<\/h2>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0637\u06cc\u06ba<\/h2>\n<p>\u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2:<\/p>\n<ul>\n<li>\n<p>\u0688\u0627\u0631\u0679 \u0627\u0648\u0631 \u0641\u0644\u0679\u0631 \u06a9\u06cc \u0646\u0634\u0648\u0648\u0646\u0645\u0627 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0622\u0631\u0627\u0645 \u062f\u06c1 \u0648\u0627\u0642\u0641\u06cc\u062a<\/p>\n<\/li>\n<li>\n<p>REST API \u06a9\u06d2 \u062a\u0635\u0648\u0631\u0627\u062a\u060c \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u06a9\u0627\u062a\u060c HTTP \u0637\u0631\u06cc\u0642\u0648\u06ba \u0627\u0648\u0631 \u0627\u0633\u0679\u06cc\u0679\u0633 \u06a9\u0648\u0688\u0632 \u06a9\u0648 \u0633\u0645\u062c\u06be\u0646\u0627\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0688\u0648\u06a9\u0631 \u0688\u06cc\u0633\u06a9 \u0679\u0627\u067e \u0627\u0646\u0633\u0679\u0627\u0644 \u0627\u0648\u0631 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>Fly.io \u0627\u06a9\u0627\u0624\u0646\u0679 (\u0645\u0641\u062a \u062f\u0631\u062c\u06d2 fly.io \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u06c1\u06d2)<\/p>\n<\/li>\n<li>\n<p>\u0641\u0644\u0627\u0626\u06cc \u0633\u06cc \u0627\u06cc\u0644 \u0622\u0626\u06cc \u0627\u0646\u0633\u0679\u0627\u0644 \u06a9\u0631\u06cc\u06ba (\u0645\u06cc\u06a9 \u0627\u0648 \u0627\u06cc\u0633 \u067e\u0631 \u0641\u0644\u0627\u0626\u06cc \u0633\u06cc \u0679\u06cc \u0627\u06cc\u0644 \u0627\u0648\u0631 \u0648\u0646\u0688\u0648\u0632\/\u0644\u06cc\u0646\u06a9\u0633 \u067e\u0631 \u0622\u0641\u06cc\u0634\u0644 \u0627\u0646\u0633\u0679\u0627\u0644\u0631 \u0628\u0646\u0627\u0626\u06cc\u06ba)<\/p>\n<\/li>\n<li>\n<p>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 PostgreSQL \u06a9\u0644\u0627\u0626\u0646\u0679 \u062c\u06cc\u0633\u06d2 TablePlus \u06cc\u0627 DBeaver &#8211; \u062f\u0648\u0646\u0648\u06ba \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u0633\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"heading-how-dart-works-on-the-server\">\u0688\u0627\u0631\u0679 \u0633\u0631\u0648\u0631\u0632 \u067e\u0631 \u06a9\u06cc\u0633\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/h2>\n<p>\u062c\u0628 \u0622\u067e \u0641\u0644\u0679\u0631 \u0627\u06cc\u067e \u0686\u0644\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u0641\u0644\u0679\u0631 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0628\u06c1\u062a \u0632\u06cc\u0627\u062f\u06c1 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062c\u0633 \u0645\u06cc\u06ba \u0648\u06cc\u062c\u06cc\u0679 \u0679\u0631\u06cc \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645 \u06a9\u0631\u0646\u0627\u060c \u0631\u06cc\u0646\u0688\u0631 \u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646 \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631\u0646\u0627\u060c \u062d\u0627\u0644\u062a \u06a9\u0648 \u0627\u06cc\u0688\u062c\u0633\u0679 \u06a9\u0631\u0646\u0627\u060c \u0627\u0648\u0631 \u067e\u0644\u06cc\u0679 \u0641\u0627\u0631\u0645 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u0627 \u062c\u0648\u0627\u0628 \u062f\u06cc\u0646\u0627 \u0634\u0627\u0645\u0644 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0627 \u0688\u0627\u0631\u0679 \u06a9\u0648\u0688 \u0627\u0646 \u0633\u0628 \u06a9\u06d2 \u0627\u0648\u067e\u0631 \u0628\u06cc\u0679\u06be\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0631\u0648\u0631 \u067e\u0631 \u06a9\u0686\u06be \u0628\u06be\u06cc \u0645\u0648\u062c\u0648\u062f \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u0648\u06cc\u062c\u06cc\u0679 \u062f\u0631\u062e\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 UI \u0644\u0627\u0626\u0641 \u0633\u0627\u0626\u06cc\u06a9\u0644 \u06a9\u0648 \u0645\u0646\u0638\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0648\u0626\u06cc \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0648 \u0635\u0631\u0641 \u06cc\u06c1 \u06a9\u0631\u0646\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0688\u0627\u0631\u0679 \u067e\u0631\u0627\u0633\u06cc\u0633 \u0686\u0644\u0627\u0626\u06cc\u06ba\u060c \u067e\u0648\u0631\u0679 \u067e\u0631 \u0633\u0646\u06cc\u06ba\u060c HTTP \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u0633\u0646\u06cc\u06ba\u060c \u06a9\u0686\u06be \u06a9\u0627\u0645 \u06a9\u0631\u06cc\u06ba\u060c \u0627\u0648\u0631 \u062c\u0648\u0627\u0628 \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4<\/p>\n<p>\u0688\u0627\u0631\u0679 \u06a9\u06cc \u0645\u0639\u06cc\u0627\u0631\u06cc \u0644\u0627\u0626\u0628\u0631\u06cc\u0631\u06cc\u060c \u0688\u0627\u0631\u0679: io\u060c \u0645\u06cc\u06ba \u0648\u06c1 \u0633\u0628 \u06a9\u0686\u06be \u06c1\u06d2 \u062c\u0633 \u06a9\u06cc \u0622\u067e \u06a9\u0648 \u0646\u0686\u0644\u06cc \u0633\u0637\u062d \u067e\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-dart\">import 'dart:io';\n\nvoid main() async {\n  final server = await HttpServer.bind('0.0.0.0', 8080);\n  print('Server running on port 8080');\n\n  await for (final request in server) {\n    request.response\n      ..statusCode = 200\n      ..write('Hello from Dart')\n      ..close();\n  }\n}\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0627\u06cc\u06a9 HTTP \u0633\u0631\u0648\u0631 \u06c1\u06d2 \u062c\u0648 \u0645\u0642\u0627\u0645\u06cc \u0688\u0627\u0631\u0679 \u067e\u0631 \u0686\u0644\u062a\u0627 \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u067e\u06cc\u06a9\u062c \u0646\u06c1\u06cc\u06ba\u060c \u06a9\u0648\u0626\u06cc \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u062a\u0645\u0627\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba HttpServer \u0633\u0679\u0631\u06cc\u0645 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0622\u062a\u06cc \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u062c\u0648\u0627\u0628 \u0645\u06cc\u06ba \u0644\u06a9\u06be\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u0633\u06d2 \u067e\u06cc\u0645\u0627\u0646\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u062c\u0633 \u0644\u0645\u062d\u06d2 \u0622\u067e \u06a9\u0648 \u0631\u0648\u0679\u0646\u06af\u060c \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631\u060c \u062a\u0648\u062b\u06cc\u0642\u060c \u0627\u0648\u0631 \u0633\u0627\u062e\u062a\u06cc \u063a\u0644\u0637\u06cc \u0633\u06d2 \u0646\u0645\u0679\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c raw dart:io \u063a\u06cc\u0631 \u0645\u0646\u0638\u0645 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0648\u06c1 \u0645\u0633\u0626\u0644\u06c1 \u06c1\u06d2 \u062c\u0633\u06d2 \u0634\u06cc\u0644\u0641 \u062d\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-what-is-shelf\">\u0644\u06cc\u062a\u06be \u06a9\u06cc\u0627 \u06c1\u06d2\u061f<\/h2>\n<p>\u0634\u06cc\u0644\u0641 \u0627\u06cc\u06a9 \u06a9\u0645\u067e\u0648\u0632 \u0627\u06cc\u0628\u0644 \u0648\u06cc\u0628 \u0633\u0631\u0648\u0631 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0644\u0627\u0626\u0628\u0631\u06cc\u0631\u06cc \u06c1\u06d2 \u062c\u0648 \u0688\u0627\u0631\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u0627\u0631\u0679 \u0679\u06cc\u0645 \u06a9\u06d2 \u0632\u06cc\u0631 \u0627\u0646\u062a\u0638\u0627\u0645 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0628\u0646\u0646\u06d2 \u06a9\u06cc \u06a9\u0648\u0634\u0634 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u06cc\u06c1 \u0628\u0644\u0688\u0646\u06af \u0628\u0644\u0627\u06a9\u0633 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0633 \u0633\u06d2 \u0622\u067e \u0627\u06cc\u06a9 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u06cc\u0627 \u0628\u0627\u0644\u06a9\u0644 \u0648\u06c1\u06cc \u062c\u0648 \u0622\u067e \u06a9\u0648 \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06d2\u06d4<\/p>\n<p>\u0634\u06cc\u0644\u0641 \u0630\u06c1\u0646\u06cc \u0645\u0627\u0688\u0644 \u0686\u0627\u0631 \u062a\u0635\u0648\u0631\u0627\u062a \u067e\u0631 \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2:<\/p>\n<ul>\n<li>\n<p><strong>\u0645\u06cc\u0646\u06cc\u062c\u0631:<\/strong> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0627\u06cc\u0633\u0627 \u0641\u0646\u06a9\u0634\u0646 \u06c1\u06d2 \u062c\u0648 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0648\u0635\u0648\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062c\u0648\u0627\u0628 \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0634\u06cc\u0644\u0641 \u067e\u0631 \u0645\u0648\u062c\u0648\u062f \u06c1\u0631 \u0686\u06cc\u0632 \u0628\u0627\u0644\u0622\u062e\u0631 \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0645\u0688\u0644 \u0648\u06cc\u0626\u0631:<\/strong> \u0627\u06cc\u06a9 \u0641\u0646\u06a9\u0634\u0646 \u062c\u0648 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06cc\u0627 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0631\u0648\u06cc\u06d2 \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0648 \u0644\u067e\u06cc\u0679\u062a\u0627 \u06c1\u06d2\u06d4 \u0644\u0627\u06af\u0646\u06af\u060c \u062a\u0648\u062b\u06cc\u0642\u060c \u0627\u0648\u0631 \u0627\u06cc\u0631\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0646\u06af \u0633\u0628\u06be\u06cc \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646:<\/strong> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0686\u06cc\u0646 \u06c1\u06d2 \u062c\u0633 \u06a9\u06d2 \u0622\u062e\u0631 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u06c1\u06cc\u0646\u0688\u0644\u0631 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u06cc\u06a9 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0686\u06cc\u0646 \u0633\u06d2 \u06af\u0632\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0631\u0627\u0624\u0679\u0631:<\/strong> \u0645\u062e\u0635\u0648\u0635 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 URL \u067e\u06cc\u0679\u0631\u0646 \u0627\u0648\u0631 HTTP \u0637\u0631\u06cc\u0642\u0648\u06ba \u06a9\u0627 \u0646\u0642\u0634\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u06af\u0631 \u0622\u067e \u0646\u06d2 \u06a9\u0628\u06be\u06cc \u0641\u0644\u0679\u0631 \u06a9\u06d2 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0679\u0631 \u06cc\u0627 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u06d2 \u062a\u0635\u0648\u0631\u0627\u062a \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06a9\u0645\u067e\u0648\u0632\u06cc\u0634\u0646 \u0645\u0627\u0688\u0644 \u0648\u0627\u0642\u0641 \u0645\u062d\u0633\u0648\u0633 \u06c1\u0648\u06af\u0627\u06d4 \u0686\u06be\u0648\u0679\u06d2\u060c \u0648\u0627\u062d\u062f \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc \u06a9\u06d2 \u0679\u06a9\u0691\u06d2 \u0627\u06cc\u06a9 \u0645\u062c\u0645\u0648\u0639\u06cc \u06a9\u0627\u0645 \u06a9\u0648 \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06a9\u0679\u06be\u06d2 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-project-setup\">\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u0627\u062a<\/h2>\n<h3 id=\"heading-creating-the-project\">\u0627\u06cc\u06a9 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<p>\u0688\u0627\u0631\u0679 \u0645\u06cc\u06ba \u0633\u0631\u0648\u0631 \u0633\u0627\u0626\u06cc\u0688 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0679\u06cc\u0645\u067e\u0644\u06cc\u0679\u0633 \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba \u062c\u0648 \u0627\u06cc\u06a9 \u0635\u0627\u0641 \u0646\u0642\u0637\u06c1 \u0622\u063a\u0627\u0632 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">dart create -t server-shelf user_profile_api\ncd user_profile_api\n<\/code><\/pre>\n<p>pubspec.yaml \u0645\u06cc\u06ba \u0645\u0637\u0644\u0648\u0628\u06c1 \u0627\u0646\u062d\u0635\u0627\u0631 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-yaml\">name: user_profile_api\ndescription: User and Profile Management REST API built with Dart and Shelf\nversion: 1.0.0\n\nenvironment:\n  sdk: '>=3.0.0 <4.0.0'\n\ndependencies:\n  shelf: ^1.4.1\n  shelf_router: ^1.1.4\n  postgres: ^3.3.0\n  dart_jsonwebtoken: ^2.12.0\n  bcrypt: ^1.1.3\n  dotenv: ^4.1.0\n  crypto: ^3.0.3\n\ndev_dependencies:\n  lints: ^3.0.0\n  test: ^1.24.0\n<\/code><\/pre>\n<p>\u0686\u0644\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">dart pub get\n<\/code><\/pre>\n<h3 id=\"heading-project-structure\">\u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u0633\u0627\u062e\u062a<\/h3>\n<p>\u0627\u0628 \u06c1\u0645 \u0627\u06cc\u06a9 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0688\u06be\u0627\u0646\u0686\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2 \u062c\u0633\u06d2 \u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0632 \u0628\u062f\u06cc\u06c1\u06cc \u0637\u0648\u0631 \u067e\u0631 \u062a\u0644\u0627\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0641\u0648\u0631\u06cc \u0637\u0648\u0631 \u067e\u0631 \u062a\u0634\u0631\u06cc\u0641 \u0644\u06d2 \u062c\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u0648\u0627\u0642\u0641 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u06a9\u0646\u0648\u0646\u0634\u0646\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u062f\u0631\u0633\u062a \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">user_profile_api\/\n  bin\/\n    server.dart              \u2190 entry point\n  lib\/\n    config\/\n      database.dart          \u2190 connection manager\n      env.dart               \u2190 environment config\n    handlers\/\n      auth_handler.dart      \u2190 auth endpoints\n      user_handler.dart      \u2190 user endpoints\n      profile_handler.dart   \u2190 profile endpoints\n    middleware\/\n      auth_middleware.dart   \u2190 JWT validation\n      error_middleware.dart  \u2190 global error handling\n      logger_middleware.dart \u2190 request logging\n    models\/\n      user.dart\n      profile.dart\n    repositories\/\n      user_repository.dart\n      profile_repository.dart\n    services\/\n      auth_service.dart      \u2190 JWT + password logic\n    router.dart              \u2190 route definitions\n  migrations\/\n    001_create_users.sql\n    002_create_profiles.sql\n  docker-compose.yml\n  Dockerfile\n  .env\n  .env.example\n<\/code><\/pre>\n<p>\u062e\u062f\u0634\u0627\u062a \u06a9\u06cc \u06cc\u06c1 \u0639\u0644\u06cc\u062d\u062f\u06af\u06cc \u0627\u0633 \u0628\u0627\u062a \u0633\u06d2 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u062a\u0639\u0644\u0642 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06d2 \u062c\u0648 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u06a9\u0648 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0645\u0639\u0644\u0648\u0645 \u06c1\u0648\u06af\u0627\u06d4 \u062f\u0648\u0633\u0631\u06d2 \u0627\u0644\u0641\u0627\u0638 \u0645\u06cc\u06ba\u060c \u0645\u0627\u0688\u0644\u0632\u060c \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u0632\u060c \u0627\u0648\u0631 \u0633\u0631\u0648\u0633\u0632 \u0627\u06cc\u06a9 \u06c1\u06cc \u062a\u0635\u0648\u0631 \u06c1\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0648\u06cc\u0648 \u0645\u0627\u0688\u0644 \u06cc\u0627 \u06a9\u0646\u0679\u0631\u0648\u0644\u0631 \u06a9\u06cc \u062c\u06af\u06c1 \u0644\u06d2 \u0644\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0627\u0646\u0679\u0631\u0633\u06cc\u067e\u0679\u0631\u0632 \u06a9\u06cc \u062c\u06af\u06c1 \u0644\u06d2 \u0644\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-database-setup-with-docker\">\u0688\u0648\u06a9\u0631 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0633\u06cc\u0679 \u0627\u067e<\/h3>\n<p>\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0631\u0648\u0679 \u0645\u06cc\u06ba docker-compose.yml \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-yaml\">version: '3.8'\n\nservices:\n  postgres:\n    image: postgres:16-alpine\n    container_name: user_profile_db\n    environment:\n      POSTGRES_DB: user_profile_api\n      POSTGRES_USER: dart_user\n      POSTGRES_PASSWORD: dart_password\n    ports:\n      - \"5432:5432\"\n    volumes:\n      - postgres_data:\/var\/lib\/postgresql\/data\n\nvolumes:\n  postgres_data:\n<\/code><\/pre>\n<p>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">docker compose up -d\n<\/code><\/pre>\n<p>\u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba \u06a9\u06c1 \u06cc\u06c1 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-bash\">docker compose ps\n# user_profile_db   running   0.0.0.0:5432->5432\/tcp\n<\/code><\/pre>\n<h3 id=\"heading-environment-configuration\">\u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628<\/h3>\n<p>\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0631\u0648\u0679 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 .env \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">DB_HOST=localhost\nDB_PORT=5432\nDB_NAME=user_profile_api\nDB_USER=dart_user\nDB_PASSWORD=dart_password\nJWT_SECRET=your_super_secret_key_change_this_in_production\nJWT_EXPIRY_HOURS=24\nPORT=8080\n<\/code><\/pre>\n<p>\u0627\u06cc\u06a9 \u06c1\u06cc \u06a9\u06cc\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u06a9 .env.example \u0628\u0646\u0627\u0626\u06cc\u06ba \u0644\u06cc\u06a9\u0646 \u06a9\u0648\u0626\u06cc \u0642\u062f\u0631 \u0646\u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u06c1\u06d2 \u062c\u0648 \u0622\u067e Git \u0633\u06d2 \u0639\u06c1\u062f \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba:<\/p>\n<pre><code class=\"language-plaintext\">DB_HOST=\nDB_PORT=\nDB_NAME=\nDB_USER=\nDB_PASSWORD=\nJWT_SECRET=\nJWT_EXPIRY_HOURS=\nPORT=\n<\/code><\/pre>\n<p>env \u06a9\u0648 .gitignore \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">.env\n<\/code><\/pre>\n<p>lib\/config\/env.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:dotenv\/dotenv.dart';\n\nclass Env {\n  static late final DotEnv _env;\n\n  static void load() {\n    _env = DotEnv(includePlatformEnvironment: true)..load();\n  }\n\n  static String get dbHost => _env['DB_HOST'] ?? 'localhost';\n  static int get dbPort => int.parse(_env['DB_PORT'] ?? '5432');\n  static String get dbName => _env['DB_NAME'] ?? 'user_profile_api';\n  static String get dbUser => _env['DB_USER'] ?? 'dart_user';\n  static String get dbPassword => _env['DB_PASSWORD'] ?? '';\n  static String get jwtSecret => _env['JWT_SECRET'] ?? '';\n  static int get jwtExpiryHours => int.parse(_env['JWT_EXPIRY_HOURS'] ?? '24');\n  static int get port => int.parse(_env['PORT'] ?? '8080');\n}\n<\/code><\/pre>\n<p>includePlatformEnvironment: true \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 Env \u06a9\u0644\u0627\u0633 .env \u0641\u0627\u0626\u0644 \u0627\u0648\u0631 \u0627\u0635\u0644 \u0633\u0633\u0679\u0645 \u06a9\u06d2 \u0645\u0627\u062d\u0648\u0644 \u06a9\u06d2 \u0645\u062a\u063a\u06cc\u0631 \u062f\u0648\u0646\u0648\u06ba \u0633\u06d2 \u067e\u0691\u06be\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0648\u06c1\u06cc \u06a9\u0648\u0688 \u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 .env \u0641\u0627\u0626\u0644 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u0648\u0631 \u0627\u0646\u062c\u06a9\u0634\u0646 \u0634\u062f\u06c1 \u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<h2 id=\"heading-shelf-core-concepts\">\u0644\u06cc\u062a\u06be \u06a9\u0644\u06cc\u062f\u06cc \u062a\u0635\u0648\u0631\u0627\u062a<\/h2>\n<p>API \u0628\u0646\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u0631 \u0634\u06cc\u0644\u0641 \u06a9\u06d2 \u062a\u0635\u0648\u0631 \u06a9\u0648 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u0633\u0645\u062c\u06be\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4 \u0627\u0633 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u0622\u067e \u06a9\u0648 \u0646\u06c1 \u0635\u0631\u0641 \u06cc\u06c1 \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u06a9\u06cc\u0627 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0628\u0644\u06a9\u06c1 \u06cc\u06c1 \u0628\u06be\u06cc \u06a9\u06c1 \u0627\u0633\u06d2 \u0627\u0633 \u0637\u0631\u062d \u06a9\u06cc\u0648\u06ba \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u062a\u06be\u0627\u06d4<\/p>\n<h3 id=\"heading-handlers\">\u06c1\u06cc\u0646\u0688\u0644\u0631<\/h3>\n<p>\u06c1\u06cc\u0646\u0688\u0644\u0631 \u0634\u06cc\u0644\u0641 \u06a9\u06cc \u0633\u0628 \u0633\u06d2 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0627\u06a9\u0627\u0626\u06cc \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0641\u0646\u06a9\u0634\u0646 \u06c1\u06d2:<\/p>\n<pre><code class=\"language-dart\">import 'package:shelf\/shelf.dart';\n\nResponse helloHandler(Request request) {\n  return Response.ok('Hello, Dart backend!');\n}\n<\/code><\/pre>\n<p>\u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0627\u0646 \u067e\u0679\u060c \u0631\u0633\u067e\u0627\u0646\u0633 \u0622\u0624\u0679 \u067e\u0679\u06d4 \u06cc\u06c1 \u0633\u0627\u0631\u06cc \u0688\u06cc\u0644 \u06c1\u06d2\u06d4 \u06c1\u0631 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06c1 \u062c\u0648 \u0622\u067e \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06c1\u06d2\u06d4 \u062a\u0645\u0627\u0645 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0627\u06cc\u06a9 \u0641\u0646\u06a9\u0634\u0646 \u06c1\u06d2 \u062c\u0648 \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0644\u06cc\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u063a\u06cc\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u06c1\u0648\u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-dart\">Future<response> getUserHandler(Request request) async {\n  final users = await userRepository.findAll();\n  return Response.ok(jsonEncode(users));\n}\n<\/response><\/code><\/pre>\n<h3 id=\"heading-request-and-response\">\u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0627\u0648\u0631 \u062c\u0648\u0627\u0628<\/h3>\n<p>\u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0622\u0646\u06d2 \u0648\u0627\u0644\u06cc HTTP \u06a9\u0627\u0644 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u062a\u0645\u0627\u0645 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-dart\">Future<response> handler(Request request) async {\n  \/\/ URL and path\n  print(request.url);           \/\/ the full URL\n  print(request.url.path);      \/\/ just the path\n\n  \/\/ Path parameters (when using shelf_router)\n  final id = request.params['id'];\n\n  \/\/ Query parameters\n  final page = request.url.queryParameters['page'];\n\n  \/\/ Headers\n  final auth = request.headers['authorization'];\n\n  \/\/ Body\n  final body = await request.readAsString();\n  final json = jsonDecode(body) as Map<string dynamic=\"\">;\n\n  return Response.ok('handled');\n}\n<\/string><\/response><\/code><\/pre>\n<p>\u062c\u0648\u0627\u0628 \u0645\u06cc\u06ba \u06a9\u0627\u0645\u0646 \u0627\u0633\u0679\u06cc\u0679\u0633 \u06a9\u0648\u0688\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0646\u0633\u0679\u0631\u06a9\u0679\u0631\u0632 \u06a9\u0627 \u0646\u0627\u0645 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-dart\">Response.ok(body)           \/\/ 200\nResponse.notFound(body)     \/\/ 404\nResponse(201, body: body)   \/\/ any status code\nResponse(400, body: body)   \/\/ bad request\nResponse(401, body: body)   \/\/ unauthorized\nResponse(500, body: body)   \/\/ server error\n<\/code><\/pre>\n<p>JSON \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a \u06c1\u0645\u06cc\u0634\u06c1 \u0645\u0648\u0627\u062f \u06a9\u06cc \u0642\u0633\u0645 \u06a9\u0627 \u06c1\u06cc\u0688\u0631 \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-dart\">Response.ok(\n  jsonEncode({'message': 'success'}),\n  headers: {'Content-Type': 'application\/json'},\n)\n<\/code><\/pre>\n<h3 id=\"heading-router\">\u0631\u0627\u0624\u0679\u0631<\/h3>\n<p>Shelf_router URL \u067e\u06cc\u0679\u0631\u0646\u0632 \u0627\u0648\u0631 HTTP \u0637\u0631\u06cc\u0642\u0648\u06ba \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0646\u0642\u0634\u06c1 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-dart\">import 'package:shelf_router\/shelf_router.dart';\n\nfinal router = Router();\n\nrouter.get('\/users', getAllUsersHandler);\nrouter.get('\/users\/<id>', getUserHandler);\nrouter.post('\/users', createUserHandler);\nrouter.put('\/users\/<id>', updateUserHandler);\nrouter.delete('\/users\/<id>', deleteUserHandler);\n<\/id><\/id><\/id><\/code><\/pre>\n<p>\u0646\u062d\u0648 \u0631\u0627\u0633\u062a\u06d2 \u06a9\u06d2 \u067e\u06cc\u0631\u0627\u0645\u06cc\u0679\u0631\u0632 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc \u062d\u0627\u0635\u0644 \u06a9\u06cc \u06af\u0626\u06cc\u06d4['id'].<\/p>\n<h3 id=\"heading-pipeline-and-middleware\">\u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646\u0632 \u0627\u0648\u0631 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631<\/h3>\n<p>\u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u0622\u062e\u0631 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062c\u0648\u0691\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-dart\">import 'package:shelf\/shelf.dart';\n\nfinal handler = Pipeline()\n    .addMiddleware(loggerMiddleware())\n    .addMiddleware(errorMiddleware())\n    .addMiddleware(authMiddleware())\n    .addHandler(router.call);\n<\/code><\/pre>\n<p>\u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u062f\u0633\u062a\u062e\u0637 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u06a9 \u0641\u0646\u06a9\u0634\u0646 \u06c1\u06d2:<\/p>\n<pre><code class=\"language-dart\">Middleware myMiddleware() {\n  return (Handler innerHandler) {\n    return (Request request) async {\n      \/\/ Before the handler runs\n      print('Request received: \\({request.method} \\){request.url}');\n\n      final response = await innerHandler(request);\n\n      \/\/ After the handler runs\n      print('Response sent: ${response.statusCode}');\n\n      return response;\n    };\n  };\n}\n<\/code><\/pre>\n<p>\u0628\u06cc\u0631\u0648\u0646\u06cc \u0627\u0641\u0639\u0627\u0644 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0648\u06c1 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0627\u06cc\u06a9 \u0641\u0646\u06a9\u0634\u0646 \u06c1\u06d2 \u062c\u0648 \u0627\u06af\u0644\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0648 \u0633\u0644\u0633\u0644\u06c1 \u0645\u06cc\u06ba \u0644\u06d2 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0646\u06cc\u0633\u0679\u0646\u06af \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06cc\u0627 \u0628\u0639\u062f \u0645\u06cc\u06ba \u06a9\u0648\u0688 \u067e\u0631 \u0639\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-connecting-to-postgresql\">PostgreSQL \u0633\u06d2 \u062c\u0691\u06cc\u06ba\u06d4<\/h2>\n<h3 id=\"heading-the-database-connection-manager\">\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0646\u06a9\u0634\u0646 \u0645\u06cc\u0646\u06cc\u062c\u0631<\/h3>\n<p>lib\/config\/database.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:postgres\/postgres.dart';\nimport 'env.dart';\n\nclass Database {\n  static Connection? _connection;\n\n  static Future<connection> get connection async {\n    if (_connection != null) return _connection!;\n    _connection = await _connect();\n    return _connection!;\n  }\n\n  static Future<connection> _connect() async {\n    final conn = await Connection.open(\n      Endpoint(\n        host: Env.dbHost,\n        port: Env.dbPort,\n        database: Env.dbName,\n        username: Env.dbUser,\n        password: Env.dbPassword,\n      ),\n      settings: const ConnectionSettings(\n        sslMode: SslMode.disable,\n      ),\n    );\n\n    print('&#x2705; Database connected: \\({Env.dbHost}:\\){Env.dbPort}\/${Env.dbName}');\n    return conn;\n  }\n\n  static Future<void> close() async {\n    await _connection?.close();\n    _connection = null;\n  }\n}\n<\/void><\/connection><\/connection><\/code><\/pre>\n<p>\u06cc\u06c1 \u0633\u0646\u06af\u0644\u0679\u0646 \u06a9\u0646\u06a9\u0634\u0646 \u0645\u06cc\u0646\u06cc\u062c\u0631 \u06c1\u06d2\u060c \u0648\u06c1\u06cc \u067e\u06cc\u0679\u0631\u0646 \u062c\u0648 \u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0632 \u0645\u0634\u062a\u0631\u06a9\u06c1 \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u067e\u06c1\u0644\u06cc \u0631\u0633\u0627\u0626\u06cc \u067e\u0631 \u0627\u06cc\u06a9 \u0628\u0627\u0631 \u0627\u06cc\u06a9 \u06a9\u0646\u06a9\u0634\u0646 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0622\u0646\u06d2 \u0648\u0627\u0644\u06cc \u062a\u0645\u0627\u0645 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0627\u0644\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-running-migrations\">\u06c1\u062c\u0631\u062a \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/h3>\n<p>\u0627\u06cc\u06a9 \u0645\u0627\u0626\u06cc\u06af\u0631\u06cc\u0634\u0646 \u0641\u0648\u0644\u0688\u0631 \u0627\u0648\u0631 \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644 \u0641\u0627\u0626\u0644 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<p>Migration\/001_create_users.sql:<\/p>\n<pre><code class=\"language-sql\">CREATE TABLE IF NOT EXISTS users (\n  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n  email VARCHAR(255) UNIQUE NOT NULL,\n  password_hash VARCHAR(255) NOT NULL,\n  first_name VARCHAR(100) NOT NULL,\n  last_name VARCHAR(100) NOT NULL,\n  is_active BOOLEAN DEFAULT TRUE,\n  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n);\n\nCREATE INDEX IF NOT EXISTS idx_users_email ON users(email);\n<\/code><\/pre>\n<p>migration\/002_create_profiles.sql:<\/p>\n<pre><code class=\"language-sql\">CREATE TABLE IF NOT EXISTS profiles (\n  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n  bio TEXT,\n  avatar_url VARCHAR(500),\n  phone VARCHAR(20),\n  location VARCHAR(255),\n  website VARCHAR(500),\n  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n  UNIQUE(user_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles(user_id);\n<\/code><\/pre>\n<p>lib\/config\/database.dart \u0645\u06cc\u06ba \u0645\u0627\u0626\u06cc\u06af\u0631\u06cc\u0634\u0646 \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0679\u0631 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-dart\">static Future<void> runMigrations() async {\n  final conn = await connection;\n  final migrationsDir = Directory('migrations');\n\n  final files = migrationsDir\n      .listSync()\n      .whereType<file>()\n      .where((f) => f.path.endsWith('.sql'))\n      .toList()\n    ..sort((a, b) => a.path.compareTo(b.path));\n\n  for (final file in files) {\n    final sql = await file.readAsString();\n    await conn.execute(sql);\n    print('&#x2705; Migration applied: ${file.path}');\n  }\n}\n<\/file><\/void><\/code><\/pre>\n<h2 id=\"heading-building-the-api\">\u0627\u06cc\u06a9 API \u0628\u0646\u0627\u0646\u0627<\/h2>\n<p>\u0627\u0628 \u062c\u0628\u06a9\u06c1 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u0646\u0633\u0644\u06a9 \u06c1\u06d2 \u0627\u0648\u0631 \u0645\u0646\u062a\u0642\u0644\u06cc \u0645\u06a9\u0645\u0644 \u06c1\u0648 \u06af\u0626\u06cc \u06c1\u06d2\u060c \u06c1\u0645 \u0627\u0635\u0644 API \u067e\u0631\u062a \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u0633\u06cc\u06a9\u0634\u0646 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0648\u0631 \u067e\u0631\u0648\u0641\u0627\u0626\u0644\u0632 \u062f\u0648\u0646\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u0627\u0688\u0644\u0632\u060c \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u0632\u060c \u0627\u0648\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u0627\u0688\u0644 \u0688\u06cc\u0679\u0627 \u06a9\u06cc \u0634\u06a9\u0644 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u062a\u0645\u0627\u0645 \u062a\u0639\u0627\u0645\u0644\u0627\u062a \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631 HTTP \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc \u06a9\u0627\u0644\u0632 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06a9\u0644\u0627\u0626\u0646\u0679 \u06a9\u0648 \u062c\u0648\u0627\u0628\u0627\u062a \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u0626\u06cc\u06d2 \u067e\u06c1\u0644\u06d2 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u06c1\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u067e\u06be\u0631 \u0627\u0633 \u06a9\u06d2 \u0627\u0648\u067e\u0631 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u06a9\u06cc \u062a\u06c1\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-the-user-model\">\u0635\u0627\u0631\u0641 \u0645\u0627\u0688\u0644<\/h3>\n<p>\u06cc\u0648\u0632\u0631 \u0645\u0627\u0688\u0644 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06cc \u0646\u0645\u0627\u0626\u0646\u062f\u06af\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u06c1\u062c\u0631\u062a \u0645\u06cc\u06ba \u0628\u0646\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0645\u06cc\u0632\u0648\u06ba \u067e\u0631 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0646\u0642\u0634\u06c1 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06cc \u0642\u0637\u0627\u0631\u0648\u06ba \u0627\u0648\u0631 \u0688\u0627\u0631\u0679 \u0622\u0628\u062c\u06cc\u06a9\u0679 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062f\u0648 \u0637\u0631\u0641\u06c1 \u062a\u0628\u062f\u06cc\u0644\u06cc \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/models\/user.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">class User {\n  final String id;\n  final String email;\n  final String passwordHash;\n  final String firstName;\n  final String lastName;\n  final bool isActive;\n  final DateTime createdAt;\n  final DateTime updatedAt;\n\n  const User({\n    required this.id,\n    required this.email,\n    required this.passwordHash,\n    required this.firstName,\n    required this.lastName,\n    required this.isActive,\n    required this.createdAt,\n    required this.updatedAt,\n  });\n\n  factory User.fromRow(Map<string dynamic=\"\"> row) => User(\n        id: row['id'] as String,\n        email: row['email'] as String,\n        passwordHash: row['password_hash'] as String,\n        firstName: row['first_name'] as String,\n        lastName: row['last_name'] as String,\n        isActive: row['is_active'] as bool,\n        createdAt: row['created_at'] as DateTime,\n        updatedAt: row['updated_at'] as DateTime,\n      );\n\n  \/\/ Never include passwordHash in JSON responses\n  Map<string dynamic=\"\"> toJson() => {\n        'id': id,\n        'email': email,\n        'firstName': firstName,\n        'lastName': lastName,\n        'isActive': isActive,\n        'createdAt': createdAt.toIso8601String(),\n        'updatedAt': updatedAt.toIso8601String(),\n      };\n}\n<\/string><\/string><\/code><\/pre>\n<p>fromRow Maps PostgreSQL \u0646\u062a\u0627\u0626\u062c \u06a9\u06cc \u0642\u0637\u0627\u0631\u06cc\u06ba \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2\u06d4 toJson \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u067e\u0627\u0633\u0648\u0631\u0688 \u06c1\u06cc\u0634 \u06a9\u0648 \u062e\u0627\u0631\u062c \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 API \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688 \u0688\u06cc\u0679\u0627 \u0648\u0627\u067e\u0633 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<h3 id=\"heading-the-user-repository\">\u0635\u0627\u0631\u0641 \u0630\u062e\u06cc\u0631\u06c1<\/h3>\n<p>UserRepository \u0622\u067e \u06a9\u06cc \u0627\u06cc\u067e\u0644\u06cc\u06a9\u06cc\u0634\u0646 \u0627\u0648\u0631 \u06cc\u0648\u0632\u0631 \u0679\u06cc\u0628\u0644 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0631\u0627\u0628\u0637\u06d2 \u06a9\u0627 \u0648\u0627\u062d\u062f \u0646\u0642\u0637\u06c1 \u06c1\u06d2\u06d4 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u062a\u0645\u0627\u0645 \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u06cc\u06c1\u0627\u06ba \u06a9\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644 \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u0648 \u0635\u0627\u0641 \u0631\u06a9\u06be\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/repositories\/user_repository.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:async';\nimport 'package:postgres\/postgres.dart';\nimport '..\/config\/database.dart';\nimport '..\/models\/user.dart';\n\nclass UserRepository {\n  Future<connection> get _conn => Database.connection;\n\n  Future<list>> findAll() async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      'SELECT * FROM users WHERE is_active = TRUE ORDER BY created_at DESC',\n    );\n\n    return results.map((row) => User.fromRow(row.toColumnMap())).toList();\n  }\n\n  Future<user> findById(String id) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('SELECT * FROM users WHERE id = @id AND is_active = TRUE'),\n      parameters: {'id': id},\n    );\n\n    if (results.isEmpty) return null;\n    return User.fromRow(results.first.toColumnMap());\n  }\n\n  Future<user> findByEmail(String email) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('SELECT * FROM users WHERE email = @email'),\n      parameters: {'email': email},\n    );\n\n    if (results.isEmpty) return null;\n    return User.fromRow(results.first.toColumnMap());\n  }\n\n  Future<user> create({\n    required String email,\n    required String passwordHash,\n    required String firstName,\n    required String lastName,\n  }) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('''\n        INSERT INTO users (email, password_hash, first_name, last_name)\n        VALUES (@email, @passwordHash, @firstName, @lastName)\n        RETURNING *\n      '''),\n      parameters: {\n        'email': email,\n        'passwordHash': passwordHash,\n        'firstName': firstName,\n        'lastName': lastName,\n      },\n    );\n\n    return User.fromRow(results.first.toColumnMap());\n  }\n\n  Future<user> update({\n    required String id,\n    String? firstName,\n    String? lastName,\n  }) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('''\n        UPDATE users\n        SET\n          first_name = COALESCE(@firstName, first_name),\n          last_name  = COALESCE(@lastName, last_name),\n          updated_at = NOW()\n        WHERE id = @id AND is_active = TRUE\n        RETURNING *\n      '''),\n      parameters: {\n        'id': id,\n        'firstName': firstName,\n        'lastName': lastName,\n      },\n    );\n\n    if (results.isEmpty) return null;\n    return User.fromRow(results.first.toColumnMap());\n  }\n\n  Future<bool> delete(String id) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('''\n        UPDATE users SET is_active = FALSE, updated_at = NOW()\n        WHERE id = @id AND is_active = TRUE\n        RETURNING id\n      '''),\n      parameters: {'id': id},\n    );\n\n    return results.isNotEmpty;\n  }\n}\n<\/bool><\/user><\/user><\/user><\/user><\/list><\/connection><\/code><\/pre>\n<p>\u06cc\u06c1\u0627\u06ba \u0686\u0646\u062f \u0628\u0627\u062a\u06cc\u06ba \u0642\u0627\u0628\u0644 \u062a\u0648\u062c\u06c1 \u06c1\u06cc\u06ba\u06d4 Sql.named \u067e\u0648\u0632\u06cc\u0634\u0646\u0644 \u067e\u06cc\u0631\u0627\u0645\u06cc\u0679\u0631\u0632 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0646\u0627\u0645\u0632\u062f \u067e\u06cc\u0631\u0627\u0645\u06cc\u0679\u0631\u0632 (@paramName) \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644 \u0627\u0646\u062c\u06cc\u06a9\u0634\u0646 \u06a9\u0648 \u0631\u0648\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u062a\u0641\u0633\u0627\u0631 \u06a9\u0648 \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u0632\u06cc\u062f \u0628\u0631\u0622\u06ba\u060c \u0688\u06cc\u0644\u06cc\u0679 \u0622\u067e\u0631\u06cc\u0634\u0646 \u0627\u06cc\u06a9 \u0646\u0631\u0645 \u0688\u06cc\u0644\u06cc\u0679 \u06c1\u06d2\u06d4 \u0642\u0637\u0627\u0631 \u06a9\u0648 \u06c1\u0679\u0627\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c is_active = FALSE \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u0639\u06cc\u0627\u0631\u06cc \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u0627 \u0637\u0631\u06cc\u0642\u06c1 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0627 \u0688\u06cc\u0679\u0627 \u062f\u0631\u062d\u0642\u06cc\u0642\u062a \u0688\u06cc\u0644\u06cc\u0679 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u0628\u0644\u06a9\u06c1 \u063a\u06cc\u0631 \u0641\u0639\u0627\u0644 \u06a9\u0631 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u067e \u0688\u06cc\u0679 \u067e\u0631 COALESCE(@firstName, first_name) \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u0627\u06af\u0631 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u06cc \u06af\u0626\u06cc \u06c1\u0648 \u062a\u0648 \u0646\u0626\u06cc \u0642\u062f\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u060c \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631 \u067e\u0631\u0627\u0646\u06cc \u0642\u062f\u0631 \u0631\u06a9\u06be\u06cc\u06ba\u06d4 \u06cc\u06c1 \u06c1\u0631 \u0628\u0627\u0631 \u062a\u0645\u0627\u0645 \u0641\u06cc\u0644\u0688\u0632 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u062c\u0632\u0648\u06cc \u0627\u067e \u0688\u06cc\u0679\u0633 \u06a9\u0648 \u0635\u0627\u0641 \u0637\u0648\u0631 \u067e\u0631 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-user-handlers\">\u0635\u0627\u0631\u0641 \u06c1\u06cc\u0646\u0688\u0644\u0631<\/h3>\n<p>\u06cc\u0648\u0632\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0644\u0627\u0633 \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u06a9\u0648 HTTP \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u0637\u0648\u0631 \u067e\u0631\u060c \u06cc\u06c1 \u0627\u06cc\u06a9 \u0631\u0627\u0624\u0679\u0631 \u0645\u062b\u0627\u0644 \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2 \u0627\u0648\u0631 \u0631\u0648\u0679\u0646\u06af \u0645\u0646\u0637\u0642 \u0627\u0648\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0644\u0627\u062c\u06a9 \u06a9\u0648 \u0627\u06cc\u06a9 \u062c\u06af\u06c1 \u067e\u0631 \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u06c1\u0631 \u0631\u0627\u0633\u062a\u06d2 \u06a9\u0648 \u0646\u062c\u06cc \u0637\u0631\u06cc\u0642\u06c1 \u067e\u0631 \u0646\u0642\u0634\u06c1 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/handlers\/user_handler.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:convert';\nimport 'package:shelf\/shelf.dart';\nimport 'package:shelf_router\/shelf_router.dart';\nimport '..\/repositories\/user_repository.dart';\n\nclass UserHandler {\n  final UserRepository _repository;\n\n  UserHandler(this._repository);\n\n  Router get router {\n    final router = Router();\n    router.get('\/', _getAll);\n    router.get('\/<id>', _getOne);\n    router.put('\/<id>', _update);\n    router.delete('\/<id>', _delete);\n    return router;\n  }\n\n  Future<response> _getAll(Request request) async {\n    final users = await _repository.findAll();\n    return Response.ok(\n      jsonEncode(users.map((u) => u.toJson()).toList()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _getOne(Request request, String id) async {\n    final user = await _repository.findById(id);\n\n    if (user == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'User not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    return Response.ok(\n      jsonEncode(user.toJson()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _update(Request request, String id) async {\n    final body = jsonDecode(await request.readAsString()) as Map<string dynamic=\"\">;\n\n    final user = await _repository.update(\n      id: id,\n      firstName: body['firstName'] as String?,\n      lastName: body['lastName'] as String?,\n    );\n\n    if (user == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'User not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    return Response.ok(\n      jsonEncode(user.toJson()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _delete(Request request, String id) async {\n    final deleted = await _repository.delete(id);\n\n    if (!deleted) {\n      return Response.notFound(\n        jsonEncode({'error': 'User not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    return Response(\n      204,\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n}\n<\/response><\/string><\/response><\/response><\/response><\/id><\/id><\/id><\/code><\/pre>\n<h3 id=\"heading-the-profile-model\">\u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0645\u0627\u0688\u0644<\/h3>\n<p>\u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0645\u0627\u0688\u0644 \u06a9\u0633\u06cc \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u062a\u0648\u0633\u06cc\u0639 \u0634\u062f\u06c1 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u06a9\u06cc \u0646\u0645\u0627\u0626\u0646\u062f\u06af\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0648 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f\u06cc \u062a\u0627\u0631\u06cc\u062e \u0633\u06d2 \u0627\u0644\u06af \u0645\u062d\u0641\u0648\u0638 \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u0648\u0646 \u0679\u0648 \u0648\u0646 \u0631\u0634\u062a\u06c1 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0679\u06cc\u0628\u0644 \u0645\u06cc\u06ba user_id \u067e\u0631 \u0627\u06cc\u06a9 \u0645\u0646\u0641\u0631\u062f \u0627\u0646\u0688\u06cc\u06a9\u0633 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0646\u0627\u0641\u0630 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0686\u0648\u0646\u06a9\u06c1 \u067e\u0631\u0648\u0641\u0627\u0626\u0644\u0632 \u062c\u0632\u0648\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0646\u0627\u0626\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0648\u0642\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0633\u0627\u062a\u06be \u0622\u0628\u0627\u062f \u06c1\u0648 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 userId \u06a9\u06d2 \u0639\u0644\u0627\u0648\u06c1 \u062a\u0645\u0627\u0645 \u0641\u06cc\u0644\u0688\u0632 null \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>lib\/models\/profile.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">class Profile {\n  final String id;\n  final String userId;\n  final String? bio;\n  final String? avatarUrl;\n  final String? phone;\n  final String? location;\n  final String? website;\n  final DateTime createdAt;\n  final DateTime updatedAt;\n\n  const Profile({\n    required this.id,\n    required this.userId,\n    this.bio,\n    this.avatarUrl,\n    this.phone,\n    this.location,\n    this.website,\n    required this.createdAt,\n    required this.updatedAt,\n  });\n\n  factory Profile.fromRow(Map<string dynamic=\"\"> row) => Profile(\n        id: row['id'] as String,\n        userId: row['user_id'] as String,\n        bio: row['bio'] as String?,\n        avatarUrl: row['avatar_url'] as String?,\n        phone: row['phone'] as String?,\n        location: row['location'] as String?,\n        website: row['website'] as String?,\n        createdAt: row['created_at'] as DateTime,\n        updatedAt: row['updated_at'] as DateTime,\n      );\n\n  Map<string dynamic=\"\"> toJson() => {\n        'id': id,\n        'userId': userId,\n        'bio': bio,\n        'avatarUrl': avatarUrl,\n        'phone': phone,\n        'location': location,\n        'website': website,\n        'createdAt': createdAt.toIso8601String(),\n        'updatedAt': updatedAt.toIso8601String(),\n      };\n}\n<\/string><\/string><\/code><\/pre>\n<h3 id=\"heading-the-profile-repository\">\u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0627\u0633\u0679\u0648\u0631<\/h3>\n<p>ProfileRepository \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0679\u06cc\u0628\u0644\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u0645\u0627\u0645 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0630\u062e\u06cc\u0631\u0648\u06ba \u06a9\u06d2 \u0628\u0631\u0639\u06a9\u0633 \u062c\u0648 ID \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u062a\u0644\u0627\u0634 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0622\u067e\u0631\u06cc\u0634\u0646 userId \u06a9\u0648 \u062a\u0644\u0627\u0634 \u06a9\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0633 \u06a9\u06cc \u0648\u062c\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0644\u0627\u0626\u0646\u0679 \u0627\u067e\u0646\u06cc \u0627\u0646\u062f\u0631\u0648\u0646\u06cc ID \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0627\u0633 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u06a9\u0627 \u062d\u0648\u0627\u0644\u06c1 \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u062c\u0633 \u0633\u06d2 \u0627\u0633 \u06a9\u0627 \u062a\u0639\u0644\u0642 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/repositories\/profile_repository.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:postgres\/postgres.dart';\nimport '..\/config\/database.dart';\nimport '..\/models\/profile.dart';\n\nclass ProfileRepository {\n  Future<connection> get _conn => Database.connection;\n\n  Future<profile> findByUserId(String userId) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('SELECT * FROM profiles WHERE user_id = @userId'),\n      parameters: {'userId': userId},\n    );\n\n    if (results.isEmpty) return null;\n    return Profile.fromRow(results.first.toColumnMap());\n  }\n\n  Future<profile> create({\n    required String userId,\n    String? bio,\n    String? avatarUrl,\n    String? phone,\n    String? location,\n    String? website,\n  }) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('''\n        INSERT INTO profiles (user_id, bio, avatar_url, phone, location, website)\n        VALUES (@userId, @bio, @avatarUrl, @phone, @location, @website)\n        RETURNING *\n      '''),\n      parameters: {\n        'userId': userId,\n        'bio': bio,\n        'avatarUrl': avatarUrl,\n        'phone': phone,\n        'location': location,\n        'website': website,\n      },\n    );\n\n    return Profile.fromRow(results.first.toColumnMap());\n  }\n\n  Future<profile> update({\n    required String userId,\n    String? bio,\n    String? avatarUrl,\n    String? phone,\n    String? location,\n    String? website,\n  }) async {\n    final conn = await _conn;\n    final results = await conn.execute(\n      Sql.named('''\n        UPDATE profiles\n        SET\n          bio        = COALESCE(@bio, bio),\n          avatar_url = COALESCE(@avatarUrl, avatar_url),\n          phone      = COALESCE(@phone, phone),\n          location   = COALESCE(@location, location),\n          website    = COALESCE(@website, website),\n          updated_at = NOW()\n        WHERE user_id = @userId\n        RETURNING *\n      '''),\n      parameters: {\n        'userId': userId,\n        'bio': bio,\n        'avatarUrl': avatarUrl,\n        'phone': phone,\n        'location': location,\n        'website': website,\n      },\n    );\n\n    if (results.isEmpty) return null;\n    return Profile.fromRow(results.first.toColumnMap());\n  }\n}\n<\/profile><\/profile><\/profile><\/connection><\/code><\/pre>\n<h3 id=\"heading-profile-handlers\">\u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u06c1\u06cc\u0646\u0688\u0644\u0631<\/h3>\n<p>ProfileHandler \u0635\u0627\u0631\u0641 ID \u06a9\u06d2 \u062a\u062d\u062a \u0627\u0646\u062f\u0631\u0648\u0646 \u062e\u0627\u0646\u06c1 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06c1\u0631 \u0622\u067e\u0631\u06cc\u0634\u0646 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0622\u06cc\u0627 \u067e\u06cc\u0631\u0646\u0679 \u0635\u0627\u0631\u0641 \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2\u06d4 \u0622\u067e \u063a\u06cc\u0631 \u0645\u0648\u062c\u0648\u062f \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u0631\u0648\u0641\u0627\u0626\u0644\u0632 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2\u060c \u062f\u0631\u0622\u0645\u062f \u06cc\u0627 \u0627\u067e \u0688\u06cc\u0679 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0633\u06a9\u062a\u06d2\u06d4 \u06cc\u06c1 \u062a\u062e\u0644\u06cc\u0642 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0632 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06a9\u06d2 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u06a9\u06cc \u0646\u0642\u0644 \u06a9\u0648 \u0628\u06be\u06cc \u0631\u0648\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/handlers\/profile_handler.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:convert';\nimport 'package:shelf\/shelf.dart';\nimport 'package:shelf_router\/shelf_router.dart';\nimport '..\/repositories\/profile_repository.dart';\nimport '..\/repositories\/user_repository.dart';\n\nclass ProfileHandler {\n  final ProfileRepository _profileRepository;\n  final UserRepository _userRepository;\n\n  ProfileHandler(this._profileRepository, this._userRepository);\n\n  Router get router {\n    final router = Router();\n    router.get('\/<userid>\/profile', _getProfile);\n    router.post('\/<userid>\/profile', _createProfile);\n    router.put('\/<userid>\/profile', _updateProfile);\n    return router;\n  }\n\n  Future<response> _getProfile(Request request, String userId) async {\n    final user = await _userRepository.findById(userId);\n    if (user == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'User not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final profile = await _profileRepository.findByUserId(userId);\n    if (profile == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'Profile not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    return Response.ok(\n      jsonEncode(profile.toJson()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _createProfile(Request request, String userId) async {\n    final user = await _userRepository.findById(userId);\n    if (user == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'User not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final existing = await _profileRepository.findByUserId(userId);\n    if (existing != null) {\n      return Response(\n        409,\n        body: jsonEncode({'error': 'Profile already exists for this user'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final body = jsonDecode(await request.readAsString()) as Map<string dynamic=\"\">;\n\n    final profile = await _profileRepository.create(\n      userId: userId,\n      bio: body['bio'] as String?,\n      avatarUrl: body['avatarUrl'] as String?,\n      phone: body['phone'] as String?,\n      location: body['location'] as String?,\n      website: body['website'] as String?,\n    );\n\n    return Response(\n      201,\n      body: jsonEncode(profile.toJson()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _updateProfile(Request request, String userId) async {\n    final body = jsonDecode(await request.readAsString()) as Map<string dynamic=\"\">;\n\n    final profile = await _profileRepository.update(\n      userId: userId,\n      bio: body['bio'] as String?,\n      avatarUrl: body['avatarUrl'] as String?,\n      phone: body['phone'] as String?,\n      location: body['location'] as String?,\n      website: body['website'] as String?,\n    );\n\n    if (profile == null) {\n      return Response.notFound(\n        jsonEncode({'error': 'Profile not found'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    return Response.ok(\n      jsonEncode(profile.toJson()),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n}\n<\/string><\/response><\/string><\/response><\/response><\/userid><\/userid><\/userid><\/code><\/pre>\n<h2 id=\"heading-authentication\">\u062b\u0628\u0648\u062a<\/h2>\n<p>\u0627\u06cc\u06a9 \u0628\u0627\u0631 \u062c\u0628 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0635\u0627\u0631\u0641 \u0627\u0648\u0631 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 CRUD \u062a\u06cc\u0627\u0631 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u0627\u06af\u0644\u0627 \u0645\u0631\u062d\u0644\u06c1 API \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0645\u06cc\u06ba \u0633\u0631\u0679\u06cc\u0641\u06cc\u06a9\u06cc\u0634\u0646 \u062f\u0648 \u062d\u0635\u0648\u06ba \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 AuthService \u062e\u0641\u06cc\u06c1 \u0646\u06af\u0627\u0631\u06cc \u06a9\u06d2 \u06a9\u0627\u0645\u0648\u06ba \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u06cc \u06c1\u06d2\u060c \u0628\u0634\u0645\u0648\u0644 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06c1\u06cc\u0634\u0646\u06af\u060c JWT \u062a\u062e\u0644\u06cc\u0642 \u0627\u0648\u0631 \u062a\u0635\u062f\u06cc\u0642\u060c \u0627\u0648\u0631 AuthHandler \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u0627\u0648\u0631 \u0644\u0627\u06af \u0627\u0646 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u0648 \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0646\u06c1\u06cc\u06ba \u06a9\u0644\u0627\u0626\u0646\u0679 \u0679\u0648\u06a9\u0646 \u062d\u0627\u0635\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0679\u0648\u06a9\u0646 \u062c\u0627\u0631\u06cc \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c AuthMiddleware \u06c1\u06cc\u0646\u0688\u0644\u0631 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u0631 \u0645\u062d\u0641\u0648\u0638 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-password-hashing\">\u067e\u0627\u0633 \u0648\u0631\u0688 \u06c1\u06cc\u0634\u0646\u06af<\/h3>\n<p>lib\/services\/auth_service.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:bcrypt\/bcrypt.dart';\nimport 'package:dart_jsonwebtoken\/dart_jsonwebtoken.dart';\nimport '..\/config\/env.dart';\nimport '..\/models\/user.dart';\n\nclass AuthService {\n  String hashPassword(String password) {\n    return BCrypt.hashpw(password, BCrypt.gensalt());\n  }\n\n  bool verifyPassword(String password, String hash) {\n    return BCrypt.checkpw(password, hash);\n  }\n\n  String generateToken(User user) {\n    final jwt = JWT(\n      {\n        'sub': user.id,\n        'email': user.email,\n        'iat': DateTime.now().millisecondsSinceEpoch ~\/ 1000,\n      },\n    );\n\n    return jwt.sign(\n      SecretKey(Env.jwtSecret),\n      expiresIn: Duration(hours: Env.jwtExpiryHours),\n    );\n  }\n\n  JWT? verifyToken(String token) {\n    try {\n      return JWT.verify(token, SecretKey(Env.jwtSecret));\n    } catch (_) {\n      return null;\n    }\n  }\n}\n<\/code><\/pre>\n<p>BCrypt.hashpw \u0646\u0645\u06a9\u06cc\u0646 \u06c1\u06cc\u0634 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 BCrypt.checkpw \u0630\u062e\u06cc\u0631\u06c1 \u0634\u062f\u06c1 \u06c1\u06cc\u0634 \u06a9\u06d2 \u062e\u0644\u0627\u0641 \u0633\u0627\u062f\u06c1 \u067e\u0627\u0633 \u0648\u0631\u0688 \u0686\u06cc\u06a9 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0646\u0645\u06a9 \u06c1\u06cc\u0634 \u0645\u06cc\u06ba \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0627\u0644\u06af \u0633\u06d2 \u0630\u062e\u06cc\u0631\u06c1 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>verifyToken \u0646\u0627\u06a9\u0627\u0645\u06cc\u060c \u0645\u06cc\u0639\u0627\u062f \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0679\u0648\u06a9\u0646\u060c \u063a\u0644\u0637 \u062f\u0633\u062a\u062e\u0637\u060c \u06cc\u0627 \u062e\u0631\u0627\u0628 \u0679\u0648\u06a9\u0646 \u067e\u0631 \u067e\u06be\u06cc\u0646\u06a9\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 null \u0644\u0648\u0679\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u0648\u062b\u06cc\u0642 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u0635\u0627\u0641 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-auth-handlers\">\u062a\u0635\u062f\u06cc\u0642 \u06c1\u06cc\u0646\u0688\u0644\u0631<\/h3>\n<p>lib\/handlers\/auth_handler.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:convert';\nimport 'package:shelf\/shelf.dart';\nimport 'package:shelf_router\/shelf_router.dart';\nimport '..\/repositories\/user_repository.dart';\nimport '..\/services\/auth_service.dart';\n\nclass AuthHandler {\n  final UserRepository _userRepository;\n  final AuthService _authService;\n\n  AuthHandler(this._userRepository, this._authService);\n\n  Router get router {\n    final router = Router();\n    router.post('\/register', _register);\n    router.post('\/login', _login);\n    return router;\n  }\n\n  Future<response> _register(Request request) async {\n    final body = jsonDecode(await request.readAsString()) as Map<string dynamic=\"\">;\n\n    final email = body['email'] as String?;\n    final password = body['password'] as String?;\n    final firstName = body['firstName'] as String?;\n    final lastName = body['lastName'] as String?;\n\n    if (email == null || password == null || firstName == null || lastName == null) {\n      return Response(\n        400,\n        body: jsonEncode({'error': 'email, password, firstName, and lastName are required'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    if (password.length < 8) {\n      return Response(\n        400,\n        body: jsonEncode({'error': 'Password must be at least 8 characters'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final existing = await _userRepository.findByEmail(email);\n    if (existing != null) {\n      return Response(\n        409,\n        body: jsonEncode({'error': 'An account with this email already exists'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final passwordHash = _authService.hashPassword(password);\n\n    final user = await _userRepository.create(\n      email: email,\n      passwordHash: passwordHash,\n      firstName: firstName,\n      lastName: lastName,\n    );\n\n    final token = _authService.generateToken(user);\n\n    return Response(\n      201,\n      body: jsonEncode({\n        'user': user.toJson(),\n        'token': token,\n      }),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n\n  Future<response> _login(Request request) async {\n    final body = jsonDecode(await request.readAsString()) as Map<string dynamic=\"\">;\n\n    final email = body['email'] as String?;\n    final password = body['password'] as String?;\n\n    if (email == null || password == null) {\n      return Response(\n        400,\n        body: jsonEncode({'error': 'email and password are required'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final user = await _userRepository.findByEmail(email);\n\n    \/\/ Deliberately vague error, never confirm whether an email exists\n    if (user == null || !_authService.verifyPassword(password, user.passwordHash)) {\n      return Response(\n        401,\n        body: jsonEncode({'error': 'Invalid email or password'}),\n        headers: {'Content-Type': 'application\/json'},\n      );\n    }\n\n    final token = _authService.generateToken(user);\n\n    return Response.ok(\n      jsonEncode({\n        'user': user.toJson(),\n        'token': token,\n      }),\n      headers: {'Content-Type': 'application\/json'},\n    );\n  }\n}\n<\/string><\/response><\/string><\/response><\/code><\/pre>\n<p>\u0644\u0627\u06af \u0627\u0646 \u06a9\u06cc \u062e\u0631\u0627\u0628\u06cc \u06a9\u06d2 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0645\u0628\u06c1\u0645 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \"\u0627\u06cc \u0645\u06cc\u0644 \u0646\u06c1\u06cc\u06ba \u0645\u0644\u0627\" \u06cc\u0627 \"\u063a\u0644\u0637 \u067e\u0627\u0633 \u0648\u0631\u0688\" \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u06cc\u06c1 \"\u063a\u0644\u0637 \u0627\u06cc \u0645\u06cc\u0644 \u06cc\u0627 \u067e\u0627\u0633 \u0648\u0631\u0688\" \u06c1\u06d2\u06d4 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0627 \u062a\u0639\u06cc\u0646 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u06a9\u06c1 \u06a9\u0648\u0646 \u0633\u0627 \u062d\u0635\u06c1 \u063a\u0644\u0637 \u06c1\u06d2 \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u06a9\u0648 \u062f\u0631\u0633\u062a \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u06a9\u06cc \u06af\u0646\u062a\u06cc \u0645\u06cc\u06ba \u0645\u062f\u062f \u0645\u0644\u06d2 \u06af\u06cc\u06d4<\/p>\n<h3 id=\"heading-auth-middleware\">\u062a\u0648\u062b\u06cc\u0642 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631<\/h3>\n<p>lib\/middleware\/auth_middleware.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:convert';\nimport 'package:shelf\/shelf.dart';\nimport '..\/services\/auth_service.dart';\n\nMiddleware authMiddleware(AuthService authService) {\n  return (Handler innerHandler) {\n    return (Request request) async {\n      final authHeader = request.headers['authorization'];\n\n      if (authHeader == null || !authHeader.startsWith('Bearer ')) {\n        return Response(\n          401,\n          body: jsonEncode({'error': 'Authorization header missing or malformed'}),\n          headers: {'Content-Type': 'application\/json'},\n        );\n      }\n\n      final token = authHeader.substring(7); \/\/ Remove 'Bearer '\n      final jwt = authService.verifyToken(token);\n\n      if (jwt == null) {\n        return Response(\n          401,\n          body: jsonEncode({'error': 'Invalid or expired token'}),\n          headers: {'Content-Type': 'application\/json'},\n        );\n      }\n\n      \/\/ Attach the user ID to the request context for downstream handlers\n      final updatedRequest = request.change(\n        context: {\n          ...request.context,\n          'userId': jwt.payload['sub'] as String,\n          'userEmail': jwt.payload['email'] as String,\n        },\n      );\n\n      return innerHandler(updatedRequest);\n    };\n  };\n}\n<\/code><\/pre>\n<p>request.change(context: {...}) \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0634\u06cc\u0644\u0641 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0633\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0648 \u0688\u06cc\u0679\u0627 \u0645\u0646\u062a\u0642\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u06cc\u06a9\u0633\u067e\u0631\u06cc\u0633 \u06cc\u0627 ASP.NET \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u067e\u0631 \u0688\u06cc\u0679\u0627 \u0645\u0646\u0633\u0644\u06a9 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0645\u062a\u0631\u0627\u062f\u0641 \u06c1\u06d2\u06d4 \u0646\u06cc\u0686\u06d2 \u06a9\u0627 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u06c1\u06cc\u0646\u0688\u0644\u0631 request.context \u067e\u0691\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4['userId'] \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u06a9\u0648\u0646 \u0633\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0645\u0633\u062a\u0646\u062f \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-error-handling\">\u06c1\u06cc\u0646\u0688\u0644\u0646\u06af \u0645\u06cc\u06ba \u062e\u0631\u0627\u0628\u06cc<\/h2>\n<p>\u0627\u0633 \u0633\u06d2 \u06a9\u0648\u0626\u06cc \u0641\u0631\u0642 \u0646\u06c1\u06cc\u06ba \u067e\u0691\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0622\u067e \u0627\u067e\u0646\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u0648 \u06a9\u062a\u0646\u06cc \u06c1\u06cc \u0627\u062d\u062a\u06cc\u0627\u0637 \u0633\u06d2 \u0644\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u0645\u06cc\u06ba \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u0646\u0627\u06a9\u0627\u0645\u06cc\u0627\u06ba \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0628\u0634\u0645\u0648\u0644 \u063a\u0644\u0637 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u0628\u0627\u0688\u06cc\u0632\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0627 \u0679\u0627\u0626\u0645 \u0622\u0624\u0679\u060c \u0627\u0648\u0631 \u063a\u06cc\u0631 \u06c1\u06cc\u0646\u0688\u0644 \u0634\u062f\u06c1 \u0627\u0633\u062a\u062b\u0646\u0627\u0626\u06cc \u0645\u0639\u0627\u0645\u0644\u0627\u062a\u06d4<\/p>\n<p>\u06c1\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0648 \u0627\u0646\u0641\u0631\u0627\u062f\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0627\u067e\u0646\u06d2 \u063a\u0644\u0637\u06cc \u06a9\u06d2 \u062c\u0648\u0627\u0628 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u06c1\u0645 \u0627\u06cc\u06a9 \u06c1\u06cc \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0645\u06cc\u06ba \u063a\u0644\u0637\u06cc \u0633\u06d2 \u0646\u0645\u0679\u0646\u06d2 \u06a9\u0648 \u0645\u0631\u06a9\u0632\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2 \u062c\u0648 \u067e\u0648\u0631\u06cc \u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646 \u06a9\u0648 \u0644\u067e\u06cc\u0679 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u0645\u0627\u0645 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u0648\u06ba \u067e\u0631 \u0645\u0633\u062a\u0642\u0644 \u063a\u0644\u0637\u06cc \u06a9\u06d2 \u062c\u0648\u0627\u0628 \u06a9\u06cc \u0634\u06a9\u0644 \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u062e\u0631\u0627\u0628\u06cc \u06a9\u06cc \u062a\u0641\u0635\u06cc\u0644\u0627\u062a \u06a9\u0648 \u06a9\u0644\u0627\u0626\u0646\u0679 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u0633\u06d2 \u0631\u0648\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>lib\/middleware\/error_middleware.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:convert';\nimport 'package:shelf\/shelf.dart';\n\nMiddleware errorMiddleware() {\n  return (Handler innerHandler) {\n    return (Request request) async {\n      try {\n        return await innerHandler(request);\n      } on FormatException catch (e) {\n        return Response(\n          400,\n          body: jsonEncode({'error': 'Invalid request body: ${e.message}'}),\n          headers: {'Content-Type': 'application\/json'},\n        );\n      } catch (e, stackTrace) {\n        \/\/ Log the full error and stack trace server-side\n        print('Unhandled error: $e');\n        print(stackTrace);\n\n        \/\/ Never expose internal error details to the client\n        return Response(\n          500,\n          body: jsonEncode({'error': 'An internal server error occurred'}),\n          headers: {'Content-Type': 'application\/json'},\n        );\n      }\n    };\n  };\n}\n<\/code><\/pre>\n<p>lib\/middleware\/logger_middleware.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:shelf\/shelf.dart';\n\nMiddleware loggerMiddleware() {\n  return (Handler innerHandler) {\n    return (Request request) async {\n      final start = DateTime.now();\n\n      final response = await innerHandler(request);\n\n      final duration = DateTime.now().difference(start).inMilliseconds;\n      print(\n        '[${DateTime.now().toIso8601String()}] '\n        '\\({request.method} \\){request.url.path} '\n        '\u2192 \\({response.statusCode} (\\){duration}ms)',\n      );\n\n      return response;\n    };\n  };\n}\n<\/code><\/pre>\n<h2 id=\"heading-wiring-everything-together\">\u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u0648 \u0622\u067e\u0633 \u0645\u06cc\u06ba \u062c\u0648\u0691\u0646\u0627<\/h2>\n<p>\u06c1\u06cc\u0646\u0688\u0644\u0631\u060c \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u060c \u0627\u0648\u0631 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be\u060c \u0622\u062e\u0631\u06cc \u0645\u0631\u062d\u0644\u06c1 \u0627\u0646 \u06a9\u0648 \u0686\u0644\u0627\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0627\u06cc\u06a9 \u0633\u0631\u0648\u0631 \u0633\u06d2 \u062c\u0648\u0691\u0646\u0627 \u06c1\u06d2\u06d4 \u0631\u0648\u0679\u0631 \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06cc\u0648 \u0622\u0631 \u0627\u06cc\u0644 \u06a9\u06d2 \u0633\u0627\u0628\u0642\u06d2 \u0646\u0642\u0634\u06d2 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u062f\u0631\u0633\u062a \u062a\u0631\u062a\u06cc\u0628 \u0645\u06cc\u06ba \u0627\u0633\u0679\u06cc\u06a9 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u0646\u0679\u0631\u06cc \u067e\u0648\u0627\u0626\u0646\u0679 \u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u0648 \u062a\u0631\u062a\u06cc\u0628 \u0633\u06d2 \u0628\u0648\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: \u0645\u0627\u062d\u0648\u0644 \u06a9\u06d2 \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u06a9\u0648 \u0644\u0648\u0688 \u06a9\u0631\u0646\u0627\u060c \u0645\u0646\u062a\u0642\u0644\u06cc \u0686\u0644\u0627\u0646\u0627\u060c \u0627\u0648\u0631 \u0633\u0631\u0648\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u0627\u06d4<\/p>\n<p>lib\/router.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'package:shelf_router\/shelf_router.dart';\nimport 'handlers\/auth_handler.dart';\nimport 'handlers\/user_handler.dart';\nimport 'handlers\/profile_handler.dart';\nimport 'middleware\/auth_middleware.dart';\nimport 'repositories\/user_repository.dart';\nimport 'repositories\/profile_repository.dart';\nimport 'services\/auth_service.dart';\n\nRouter createRouter() {\n  final userRepository = UserRepository();\n  final profileRepository = ProfileRepository();\n  final authService = AuthService();\n\n  final authHandler = AuthHandler(userRepository, authService);\n  final userHandler = UserHandler(userRepository);\n  final profileHandler = ProfileHandler(profileRepository, userRepository);\n\n  final router = Router();\n\n  \/\/ Public routes, no auth required\n  router.mount('\/auth', authHandler.router.call);\n\n  \/\/ Protected routes, auth middleware applied\n  router.mount(\n    '\/users',\n    Pipeline()\n        .addMiddleware(authMiddleware(authService))\n        .addHandler(userHandler.router.call),\n  );\n\n  router.mount(\n    '\/users',\n    Pipeline()\n        .addMiddleware(authMiddleware(authService))\n        .addHandler(profileHandler.router.call),\n  );\n\n  return router;\n}\n<\/code><\/pre>\n<p>\u0627\u0646\u0679\u0631\u06cc \u067e\u0648\u0627\u0626\u0646\u0679 bin\/server.dart \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-dart\">import 'dart:io';\nimport 'package:shelf\/shelf.dart';\nimport 'package:shelf\/shelf_io.dart' as shelf_io;\nimport '..\/lib\/config\/database.dart';\nimport '..\/lib\/config\/env.dart';\nimport '..\/lib\/middleware\/error_middleware.dart';\nimport '..\/lib\/middleware\/logger_middleware.dart';\nimport '..\/lib\/router.dart';\n\nvoid main() async {\n  \/\/ Load environment variables\n  Env.load();\n\n  \/\/ Run database migrations\n  await Database.runMigrations();\n\n  \/\/ Build the handler pipeline\n  final router = createRouter();\n\n  final handler = Pipeline()\n      .addMiddleware(errorMiddleware())\n      .addMiddleware(loggerMiddleware())\n      .addHandler(router.call);\n\n  \/\/ Start the server\n  final server = await shelf_io.serve(\n    handler,\n    InternetAddress.anyIPv4,\n    Env.port,\n  );\n\n  print('&#x1f680; Server running on port ${server.port}');\n}\n<\/code><\/pre>\n<p>\u0633\u0631\u0648\u0631 \u0686\u0644\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">dart run bin\/server.dart\n# &#x2705; Database connected: localhost:5432\/user_profile_api\n# &#x2705; Migration applied: migrations\/001_create_users.sql\n# &#x2705; Migration applied: migrations\/002_create_profiles.sql\n# &#x1f680; Server running on port 8080\n<\/code><\/pre>\n<h2 id=\"heading-deployment\">\u062a\u0639\u06cc\u0646\u0627\u062a\u06cc<\/h2>\n<p>\u0633\u0631\u0648\u0631 \u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062a\u0645\u0627\u0645 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06d2 \u0627\u0648\u067e\u0631 \u06c1\u06cc\u06ba\u06d4 \u0627\u0628 \u062c\u06c1\u0627\u0632 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u06a9\u0627 \u0648\u0642\u062a \u0622\u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u06d2 \u062f\u0648 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u06cc\u06ba \u06af\u06d2: \u067e\u06c1\u0644\u06d2\u060c \u0645\u0642\u0627\u0645\u06cc \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0679\u06cc\u0633\u0679\u0646\u06af \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u0648\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u067e \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0648 \u067e\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u060c \u067e\u06be\u0631 \u0627\u0633\u06d2 Fly.io \u067e\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u06cc\u06ba\u060c \u062c\u06c1\u0627\u06ba \u0627\u06cc\u06a9 \u0645\u0646\u0638\u0645 PostgreSQL \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0627\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 TLS \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 API \u0627\u0646\u0679\u0631\u0646\u06cc\u0679 \u067e\u0631 \u0642\u0627\u0628\u0644 \u0631\u0633\u0627\u0626\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-dockerfile\">\u0688\u0627\u06a9\u0631 \u0641\u0627\u0626\u0644<\/h3>\n<p>\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0631\u0648\u0679 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0688\u0627\u06a9\u0631 \u0641\u0627\u0626\u0644 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-dockerfile\">FROM dart:stable AS build\n\nWORKDIR \/app\nCOPY pubspec.* .\/\nRUN dart pub get\n\nCOPY . .\nRUN dart compile exe bin\/server.dart -o bin\/server\n\nFROM debian:stable-slim\n\nRUN apt-get update && apt-get install -y ca-certificates && rm -rf \/var\/lib\/apt\/lists\/*\n\nWORKDIR \/app\nCOPY --from=build \/app\/bin\/server bin\/server\nCOPY --from=build \/app\/migrations migrations\/\n\nEXPOSE 8080\n\nCMD [\"bin\/server\"]\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0627\u06cc\u06a9 \u06a9\u062b\u06cc\u0631 \u0645\u0631\u062d\u0644\u06c1 \u062a\u0639\u0645\u06cc\u0631 \u06c1\u06d2\u06d4 \u067e\u06c1\u0644\u0627 \u0645\u0631\u062d\u0644\u06c1 \u0633\u0631\u0648\u0631 \u06a9\u0648 \u0645\u0642\u0627\u0645\u06cc \u0628\u0627\u0626\u0646\u0631\u06cc\u0632 \u0645\u06cc\u06ba \u0645\u0631\u062a\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u06a9\u0645\u0644 \u0688\u0627\u0631\u0679 SDK \u0627\u0645\u06cc\u062c \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0648\u0633\u0631\u06d2 \u0645\u0631\u062d\u0644\u06d2 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u0635\u0631\u0641 \u0645\u0631\u062a\u0628 \u0634\u062f\u06c1 \u0628\u0627\u0626\u0646\u0631\u06cc\u0632 \u06a9\u0627\u067e\u06cc \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0646\u06c1\u06cc\u06ba \u06a9\u0645 \u0633\u06d2 \u06a9\u0645 \u0688\u06cc\u0628\u06cc\u0646 \u0627\u0645\u06cc\u062c \u0645\u06cc\u06ba \u0645\u0646\u062a\u0642\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u0688\u0627\u0631\u0679 SDK\u060c \u0633\u0648\u0631\u0633 \u06a9\u0648\u0688\u060c \u06cc\u0627 \u0628\u0644\u0688 \u0679\u0648\u0644\u0632 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u062d\u062a\u0645\u06cc \u062a\u0635\u0648\u06cc\u0631 \u062c\u0627\u0645\u0639 \u0627\u0648\u0631 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-docker-compose-for-local-production-testing\">\u0645\u0642\u0627\u0645\u06cc \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u0648\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632<\/h3>\n<p>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u067e \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 docker-compose.yml \u06a9\u0648 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-yaml\">version: '3.8'\n\nservices:\n  postgres:\n    image: postgres:16-alpine\n    container_name: user_profile_db\n    environment:\n      POSTGRES_DB: user_profile_api\n      POSTGRES_USER: dart_user\n      POSTGRES_PASSWORD: dart_password\n    ports:\n      - \"5432:5432\"\n    volumes:\n      - postgres_data:\/var\/lib\/postgresql\/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U dart_user -d user_profile_api\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n\n  api:\n    build: .\n    container_name: user_profile_api\n    ports:\n      - \"8080:8080\"\n    environment:\n      DB_HOST: postgres\n      DB_PORT: 5432\n      DB_NAME: user_profile_api\n      DB_USER: dart_user\n      DB_PASSWORD: dart_password\n      JWT_SECRET: local_test_secret_replace_in_production\n      JWT_EXPIRY_HOURS: 24\n      PORT: 8080\n    depends_on:\n      postgres:\n        condition: service_healthy\n\nvolumes:\n  postgres_data:\n<\/code><\/pre>\n<p>\u067e\u0648\u0633\u0679\u06af\u0631\u06cc\u0633 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u0635\u062d\u062a \u06a9\u06cc \u062c\u0627\u0646\u0686 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u06cc \u06c1\u06d2 \u06a9\u06c1 API \u06a9\u0646\u0679\u06cc\u0646\u0631 \u0635\u0631\u0641 \u0627\u0633 \u0648\u0642\u062a \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u062c\u0628 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0646\u06a9\u0634\u0646 \u06a9\u0648 \u0642\u0628\u0648\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u06c1\u0648 (\u062c\u0628 \u062e\u062f\u0645\u0627\u062a \u0628\u06cc\u06a9 \u0648\u0642\u062a \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u06cc \u06c1\u06cc\u06ba \u062a\u0648 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u06a9\u0627 \u0627\u06cc\u06a9 \u0639\u0627\u0645 \u0645\u0633\u0626\u0644\u06c1)\u06d4<\/p>\n<p>\u0633\u0628 \u06a9\u0686\u06be \u0628\u0646\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">docker compose up --build\n<\/code><\/pre>\n<h3 id=\"heading-deploying-to-flyio\">Fly.io \u067e\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>Fly.io \u06a9\u0646\u0679\u06cc\u0646\u0631\u0627\u0626\u0632\u0688 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0633\u0631\u0648\u0633\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0635\u0627\u0641 \u062a\u0631\u06cc\u0646 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u0627\u06c1\u062f\u0627\u0641 \u0645\u06cc\u06ba \u0633\u06d2 \u0627\u06cc\u06a9 \u06c1\u06d2\u06d4 \u0639\u0627\u0644\u0645\u06cc \u062a\u0642\u0633\u06cc\u0645\u060c \u062e\u0648\u062f\u06a9\u0627\u0631 TLS\u060c \u0627\u0648\u0631 \u0646\u0638\u0645 \u0634\u062f\u06c1 PostgreSQL \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p><strong>\u0645\u0631\u062d\u0644\u06c1 1 - \u062a\u0646\u0635\u06cc\u0628 \u0627\u0648\u0631 \u0633\u0631\u0679\u06cc\u0641\u06cc\u06a9\u06cc\u0634\u0646:<\/strong><\/p>\n<pre><code class=\"language-bash\"># macOS\nbrew install flyctl\n\n# Authenticate\nfly auth login\n<\/code><\/pre>\n<p><strong>\u0645\u0631\u062d\u0644\u06c1 2 - \u0627\u06cc\u067e \u0686\u0644\u0627\u0626\u06cc\u06ba:<\/strong><\/p>\n<pre><code class=\"language-bash\">fly launch\n<\/code><\/pre>\n<p>Fly \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u0622\u067e \u06a9\u06cc Dockerfile \u06a9\u0627 \u067e\u062a\u06c1 \u0644\u06af\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0622\u067e \u06a9\u06d2 \u0627\u06cc\u067e \u06a9\u0627 \u0646\u0627\u0645\u060c \u0639\u0644\u0627\u0642\u06c1 \u0627\u0648\u0631 \u06a9\u06cc\u0627 \u0622\u067e PostgreSQL \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0628\u0646\u0627\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u0633\u0645\u06cc\u062a \u0686\u0646\u062f \u0633\u0648\u0627\u0644\u0627\u062a \u067e\u0648\u0686\u06be\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e PostgreSQL \u067e\u0631\u0627\u0645\u067e\u0679 \u06a9\u0627 \u062c\u0648\u0627\u0628 \u06c1\u0627\u06ba \u0645\u06cc\u06ba \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 Fly \u0622\u067e \u06a9\u06d2 \u0632\u06cc\u0631 \u0627\u0646\u062a\u0638\u0627\u0645 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0648 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u06d2 \u06af\u0627 \u0627\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u0637\u0648\u0631 \u067e\u0631 \u06a9\u0646\u06a9\u0634\u0646 \u0633\u0679\u0631\u0646\u06af \u062f\u0627\u062e\u0644 \u06a9\u0631 \u062f\u06d2 \u06af\u0627\u06d4<\/p>\n<p><strong>\u0645\u0631\u062d\u0644\u06c1 3 - \u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba:<\/strong><\/p>\n<pre><code class=\"language-bash\">fly secrets set JWT_SECRET=\"your_production_secret_here\"\nfly secrets set JWT_EXPIRY_HOURS=\"24\"\n<\/code><\/pre>\n<p>\u062c\u0628 \u0622\u067e PostgreSQL \u06a9\u0644\u0633\u0679\u0631 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0646\u06a9\u0634\u0646 \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u062e\u0648\u062f \u0628\u062e\u0648\u062f Fly \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0633\u06cc\u0679 \u06c1\u0648 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><strong>\u0645\u0631\u062d\u0644\u06c1 4 - \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u06cc\u06ba:<\/strong><\/p>\n<pre><code class=\"language-bash\">fly deploy\n<\/code><\/pre>\n<p>\u0641\u0644\u0627\u0626\u06cc \u0688\u0648\u06a9\u0631 \u0627\u0645\u06cc\u062c\u0632 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0646\u06c1\u06cc\u06ba \u0622\u067e \u06a9\u06cc \u0631\u062c\u0633\u0679\u0631\u06cc \u0645\u06cc\u06ba \u062f\u06be\u06a9\u06cc\u0644\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u0646\u06c1\u06cc\u06ba \u0627\u067e\u0646\u06cc \u067e\u0633\u0646\u062f \u06a9\u06d2 \u0639\u0644\u0627\u0642\u06d2 \u0645\u06cc\u06ba \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f:<\/p>\n<pre><code class=\"language-bash\">fly status\n# Your app is running at https:\/\/your-app-name.fly.dev\n<\/code><\/pre>\n<p><strong>\u0645\u0631\u062d\u0644\u06c1 5 - \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u06cc\u06ba:<\/strong><\/p>\n<pre><code class=\"language-bash\">curl https:\/\/your-app-name.fly.dev\/auth\/register \\\n  -X POST \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"email\":\"test@example.com\",\"password\":\"password123\",\"firstName\":\"Seyi\",\"lastName\":\"Dev\"}'\n<\/code><\/pre>\n<h2 id=\"heading-testing-the-api\">API \u0679\u06cc\u0633\u0679\u0646\u06af<\/h2>\n<p>\u0627\u06af\u0631 \u0622\u067e \u06a9\u0627 \u0633\u0631\u0648\u0631 \u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u067e\u0648\u0631\u0679 8080 \u067e\u0631 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u06c1 \u06c1\u0631 \u0686\u06cc\u0632 \u0627\u062e\u062a\u062a\u0627\u0645 \u0633\u06d2 \u0622\u062e\u0631 \u062a\u06a9 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u0645\u06a9\u0645\u0644 \u0628\u06c1\u0627\u0624 \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06d2:<\/p>\n<p>\u0635\u0627\u0631\u0641 \u06a9\u06cc \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646:<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/auth\/register \\\n  -X POST \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"email\": \"seyi@example.com\",\n    \"password\": \"securepassword\",\n    \"firstName\": \"Seyi\",\n    \"lastName\": \"Dev\"\n  }'\n<\/code><\/pre>\n<p>\u062c\u0648\u0627\u0628:<\/p>\n<pre><code class=\"language-json\">{\n  \"user\": {\n    \"id\": \"uuid-here\",\n    \"email\": \"seyi@example.com\",\n    \"firstName\": \"Seyi\",\n    \"lastName\": \"Dev\",\n    \"isActive\": true,\n    \"createdAt\": \"2025-01-01T00:00:00.000Z\",\n    \"updatedAt\": \"2025-01-01T00:00:00.000Z\"\n  },\n  \"token\": \"eyJhbGci...\"\n}\n<\/code><\/pre>\n<p>\u0644\u0627\u06af \u0627\u0646:<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/auth\/login \\\n  -X POST \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"email\": \"seyi@example.com\", \"password\": \"securepassword\"}'\n<\/code><\/pre>\n<p>\u062a\u0645\u0627\u0645 \u0635\u0627\u0631\u0641\u06cc\u0646 \u062d\u0627\u0635\u0644 \u06a9\u0631\u06cc\u06ba (\u062a\u0635\u062f\u06cc\u0642 \u0634\u062f\u06c1):<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/users \\\n  -H \"Authorization: Bearer eyJhbGci...\"\n<\/code><\/pre>\n<p>\u0627\u067e\u0646\u0627 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0628\u0646\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/users\/{userId}\/profile \\\n  -X POST \\\n  -H \"Authorization: Bearer eyJhbGci...\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"bio\": \"Flutter engineer turned backend developer\",\n    \"location\": \"Lagos, Nigeria\",\n    \"website\": \"https:\/\/example.com\"\n  }'\n<\/code><\/pre>\n<p>\u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0627\u0632\u06c1 \u06a9\u0627\u0631\u06cc\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/users\/{userId} \\\n  -X PUT \\\n  -H \"Authorization: Bearer eyJhbGci...\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"firstName\": \"Oluwaseyi\"}'\n<\/code><\/pre>\n<p>\u0635\u0627\u0631\u0641 \u06a9\u0648 \u062d\u0630\u0641 \u06a9\u0631\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/users\/{userId} \\\n  -X DELETE \\\n  -H \"Authorization: Bearer eyJhbGci...\"\n<\/code><\/pre>\n<h2 id=\"heading-conclusion\">\u0646\u062a\u06cc\u062c\u06c1<\/h2>\n<p>\u06c1\u0645 \u0646\u06d2 Dart \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u06af\u0631\u06cc\u0688 REST API \u0628\u0646\u0627\u06cc\u0627 \u0627\u0648\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u06cc\u0627\u060c \u0648\u06c1\u06cc \u0632\u0628\u0627\u0646 \u062c\u0648 \u06c1\u0645 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 Flutter \u0633\u06d2 \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u0646\u0626\u06cc \u0632\u0628\u0627\u0646 \u0646\u06c1\u06cc\u06ba\u060c \u06a9\u0648\u0626\u06cc \u0646\u06cc\u0627 \u0646\u0645\u0648\u0646\u06c1 \u0646\u06c1\u06cc\u06ba\u06d4 \u0688\u0627\u0631\u0679 \u0645\u062e\u062a\u0644\u0641 \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u0645\u06cc\u06ba \u0686\u0644\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0634\u06cc\u0644\u0641 \u0630\u06c1\u0646\u06cc \u0645\u0627\u0688\u0644 (\u06c1\u06cc\u0646\u0688\u0644\u0631\u060c \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631\u060c \u067e\u0627\u0626\u067e \u0644\u0627\u0626\u0646\u0632\u060c \u0631\u0648\u0679\u0631\u0632) \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u06a9\u0645 \u0633\u06d2 \u06a9\u0645 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0622\u067e \u06a9\u06d2 \u0644\u06cc\u06d2 \u0641\u06cc\u0635\u0644\u06d2 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0642\u0627\u0628\u0644 \u062a\u0631\u062a\u06cc\u0628 \u067e\u0631\u0627\u0626\u0645\u06cc\u0679\u0648\u0632 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0622\u067e \u06a9\u0648 \u0627\u0646 \u06a9\u0648 \u0628\u0627\u0644\u06a9\u0644 \u0627\u0633\u06cc \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u0645\u06cc\u06ba \u062c\u0648\u0691\u0646\u06d2 \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u062c\u0633 \u06a9\u06cc \u0622\u067e \u06a9\u06d2 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0641\u0644\u0633\u0641\u06c1 \u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0632 \u06a9\u0648 \u0648\u0627\u0642\u0641 \u0645\u062d\u0633\u0648\u0633 \u06a9\u0631\u06d2 \u06af\u0627\u060c \u062c\u0648 \u0646\u0633\u062e\u06d2 \u06a9\u06d2 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u067e\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u067e\u0646\u0627 \u0635\u0627\u0641 \u0633\u062a\u06be\u0631\u0627 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1\u0627\u06ba \u0628\u0646\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0645\u0627\u0688\u0644\u0632\u060c \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u0632\u060c \u0633\u0631\u0648\u0633\u0632\u060c \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632\u060c \u0627\u0648\u0631 \u0645\u0688\u0644 \u0648\u06cc\u0626\u0631 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u067e\u0631 \u062e\u062f\u0634\u0627\u062a \u06a9\u06cc \u0648\u06c1\u06cc \u0639\u0644\u06cc\u062d\u062f\u06af\u06cc \u0644\u0627\u06af\u0648 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u0641\u0644\u0679\u0631 \u0645\u06cc\u06ba \u0644\u0627\u06af\u0648 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u062a\u0635\u0648\u0631 \u0645\u0646\u062a\u0642\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0688\u0627\u0631\u0679 \u0679\u06cc\u06a9\u0646\u0627\u0644\u0648\u062c\u06cc \u06a9\u06cc \u0645\u0646\u062a\u0642\u0644\u06cc \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u0627 \u0645\u06cc\u062f\u0627\u0646 \u062a\u0628\u062f\u06cc\u0644 \u06c1\u0648 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2\u060c \u0622\u067e \u0633\u0645\u062c\u06be\u06cc\u06ba \u06af\u06d2 \u06a9\u06c1 \u0688\u0627\u0631\u0679 \u0627\u06cc\u06a9 \u0637\u0627\u0642\u062a\u0648\u0631 \u0632\u0628\u0627\u0646 \u06c1\u06d2 \u062c\u0648 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0627\u0648\u0631 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0627\u06cc\u06a9\u0648 \u0633\u0633\u0679\u0645 \u062f\u0648\u0646\u0648\u06ba \u067e\u0631 \u0645\u062d\u06cc\u0637 \u06c1\u06d2\u06d4 \u0634\u06cc\u0644\u0641 \u06a9\u06d2 \u0639\u0644\u0627\u0648\u06c1\u060c \u0688\u0627\u0631\u0679 \u0641\u0631\u0627\u06af \u0627\u0648\u0631 \u0633\u0631\u0648\u0631 \u067e\u0648\u0688 \u06c1\u06cc\u06ba \u062c\u0648 \u0627\u0628 \u0628\u06be\u06cc \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0633\u0627\u0626\u06cc\u0688 \u067e\u0631 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0645\u0633\u062a\u0642\u0628\u0644 \u06a9\u06d2 \u0645\u0636\u0645\u0648\u0646 \u0645\u06cc\u06ba \u0627\u0633 \u067e\u0631 \u0645\u0632\u06cc\u062f\u06d4<\/p>\n<p>\u06c1\u0627\u06ba\u060c \u0627\u0633\u06d2 \u0622\u0632\u0645\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0645\u06cc\u0631\u0627 \u0634\u06a9\u0631\u06cc\u06c1!<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u0641\u0644\u0679\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0622\u067e \u0688\u0627\u0631\u0679 \u06a9\u0648 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 async\/\u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0648 \u0633\u0645\u062c\u06be\u06cc\u06ba\u060c \u0645\u0627\u0688\u0644\u0632 \u0627\u0648\u0631 \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645 \u06a9\u0631\u06cc\u06ba\u060c \u0635\u0627\u0641 \u0622\u0631\u06a9\u06cc\u0679\u06cc\u06a9\u0686\u0631\u0632 \u0645\u06cc\u06ba \u0633\u0648\u0686\u06cc\u06ba\u060c \u0627\u0648\u0631 \u062d\u0642\u06cc\u0642\u06cc \u0627\u06cc\u067e\u0644\u06cc \u06a9\u06cc\u0634\u0646\u0632 \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4 \u0622\u067e \u0622\u062c \u06a9\u06c1\u0627\u06ba \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062c\u06c1\u0627\u06ba \u0622\u067e \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u0627\u0648\u0631 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0633 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0641\u0631\u0642 \u0622\u067e \u06a9\u06d2 \u062e\u06cc\u0627\u0644 [&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-24806","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/24806","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/comments?post=24806"}],"version-history":[{"count":0,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/24806\/revisions"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/media?parent=24806"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/categories?post=24806"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/tags?post=24806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}