{"id":480575,"date":"2026-05-21T22:16:38","date_gmt":"2026-05-21T22:16:38","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=480575"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=480575","title":{"rendered":"\u041a\u0430\u043a \u044f \u0431\u0435\u0437 \u043d\u0430\u0432\u044b\u043a\u043e\u0432 fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u0432\u043e\u0439 SaaS"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u0425\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0442\u0435\u043c, \u043a\u0430\u043a \u044f, \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0431\u0435\u0437 \u043d\u0430\u0432\u044b\u043a\u043e\u0432 fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0441\u0434\u0435\u043b\u0430\u043b, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u044b\u0439 SaaS. \u0412\u0435\u0441\u044c \u0442\u0435\u043a\u0441\u0442 &#8212; \u043c\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u043c\u044b\u0441\u043b\u0435\u0439 \u0438 \u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439. <\/p>\n<p>\u041c\u043e\u0451 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e: MacBook Air M2, 16 \u0413\u0411. \u0423 \u043c\u0435\u043d\u044f \u043d\u0435\u0442 \u043e\u043f\u044b\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0431\u0438\u0433\u0442\u0435\u0445\u0435, \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0432 \u043a\u0430\u043a\u043e\u043c \u043b\u0438\u0431\u043e \u0442\u0435\u0445\u0435, \u0445\u0435\u0445\u0435 \ud83d\ude42<\/p>\n<hr\/>\n<p>\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 2025 \u0433\u043e\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0435\u0445\u0430\u043b \u0432 \u0433\u043e\u0441\u0442\u0438 \u043a \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0430\u0437\u0434\u043d\u043e\u0432\u0430\u0442\u044c \u041d\u043e\u0432\u044b\u0439 \u0433\u043e\u0434, \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043d\u0435\u0431\u044b\u0432\u0430\u043b\u043e\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u2014 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. ChatGPT, Grok, Claude, YouTube, Telegram \u2014 \u0432\u0441\u0451. \u041c\u043e\u0439 \u0440\u043e\u0434\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u043e\u043d \u0431\u044b\u043b \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0430 \u043a\u043e\u043c \u0420\u041a\u041d \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0431\u0435\u043b\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438.<\/p>\n<p>\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a OpenVPN \u2014 \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u044b \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043b\u0438 \u043a\u043b\u044e\u0447\u0438 \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f. \u0414\u0430, \u0441 \u043c\u043e\u0435\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0436\u0435\u043d\u0438\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\u044e. \u041d\u043e \u043c\u0435\u043d\u044f \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u043e, \u043f\u043e\u043a\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 2025 \u0433\u043e\u0434\u0430 OpenVPN \u043d\u0435 \u0437\u0430\u0431\u0430\u043d\u0438\u043b\u0438. \u041c\u043e\u0439 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u043b \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u043a \u0441\u0432\u043e\u0435\u0439 \u0441\u0435\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e, \u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0441\u0435\u0442 \u043b\u0430\u043f\u0443.  <\/p>\n<p>\u042f \u043d\u0435 \u0433\u043e\u0442\u043e\u0432 \u043c\u0438\u0440\u0438\u0442\u044c\u0441\u044f \u0441 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430\u043c\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432\u0441\u0451 \u0435\u0449\u0451 \u0432 \u0440\u0435\u0433\u0438\u043e\u043d\u0435, \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430\u00a0<em>\u043d\u0435\u0433\u043e<\/em>\u00a0\u2014 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0<strong>Hysteria2<\/strong>. \u0411\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b VPS, \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0438 \u0431\u044b\u043b \u0440\u0430\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044e \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043c\u0438\u0440.<\/p>\n<p>\u041d\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u043e\u043a\u0438 \u043c\u0435\u043d\u044f \u0437\u0430\u0446\u0435\u043f\u0438\u043b\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041f\u043e \u0441\u0443\u0442\u0438 \u2014 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u0443\u0434\u043e\u0431\u043d\u043e \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u0432\u0430\u043b \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 API.<\/p>\n<hr\/>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0444\u0435\u0432\u0440\u0430\u043b\u044f 2026 \u0433\u043e\u0434\u0430 \u043c\u043d\u0435 \u043f\u043e\u043f\u0430\u043b\u043e\u0441\u044c \u0432\u0438\u0434\u0435\u043e \u043d\u0430 YouTube \u2014\u00a0<a href=\"https:\/\/youtu.be\/ckL6kEG2BOk?si=BW5ZtoNV066ggYzP\" rel=\"noopener noreferrer nofollow\">\u00ab\u041a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043e\u043f\u043b\u0430\u0442\u0430 \u043a\u0430\u0440\u0442\u043e\u0439\u00bb<\/a>. \u042d\u0442\u043e \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e \u043c\u043d\u0435, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 REST API, \u0438 \u0434\u0430\u043b\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u0438\u0435: \u0438\u0437 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0435. \u041c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0447\u0442\u043e \u044f \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c MacBook \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u044b\u043b \u0433\u043e\u0442\u043e\u0432 \u043f\u043e\u0434\u0451\u0440\u0433\u0430\u0442\u044c \u0435\u0433\u043e \u0437\u0430 \u0440\u0443\u0447\u043a\u0438.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u0443\u0440\u043b\u0430\u043c\u0438, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u043b\u0430 \u043c\u044b\u0441\u043b\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 Python. \u041f\u0435\u0440\u0432\u043e\u0435, \u0441 \u0447\u0435\u043c \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u00a0<code>requests<\/code>.<\/p>\n<p>\u0421 \u0438\u0438\u0448\u043a\u043e\u0439 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u043d\u0430\u043a\u0430\u0442\u0430\u043b\u0438 \u043a\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043d\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u0412\u043e\u0442 \u043a\u0443\u0441\u043e\u0447\u0435\u043a:<\/p>\n<pre><code class=\"python\">API_HOST   = \"127.0.0.1\"API_PORT   = 8080API_SECRET = \"sixseven\"USERS = {    \"s\"   : \"ss\",    \"user\": \"password\",    \"test\": \"12345\",}ALLOWED = {    \"s\"   : False,    \"user\": True,    \"test\": False,}def get_online_users():    url = f\"http:\/\/{API_HOST}:{API_PORT}\/online\"    headers = {\"Authorization\": API_SECRET}    try:        r = requests.get(url, headers=headers, timeout=5)        r.raise_for_status()           # \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0435\u0441\u043b\u0438 \u043d\u0435 200        return r.json()                # {\"username\": connection_count, ...}    except requests.exceptions.HTTPError as e:        print(f\"API \u0432\u0435\u0440\u043d\u0443\u043b \u043e\u0448\u0438\u0431\u043a\u0443 {r.status_code}: {r.text}\")        return {}    except requests.exceptions.RequestException as e:        print(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a API: {e}\")        return {}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u0435 \u0431\u0443\u0434\u0443 \u0432\u0440\u0430\u0442\u044c, \u043d\u0430 \u043d\u043e\u0432\u0438\u0447\u043a\u0430 \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0432\u043e\u0441\u0445\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u044d\u0442\u0438\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 VPN-\u0441\u0435\u0440\u0432\u0438\u0441. \u0418\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u0441\u0442\u0432\u043e.<\/p>\n<hr\/>\n<p>\u041d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430. \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u043b \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u0442\u0440\u0438 \u0447\u0430\u0441\u0442\u0438: backend, frontend, Hysteria2 \u2014 \u0442\u0440\u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0437\u043e\u043d\u044b \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f. \u0422\u0430\u043a \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441\u00a0<strong>Docker Compose<\/strong>. \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0434\u043b\u044f Hysteria2 \u0443\u0436\u0435 \u0442\u044f\u043d\u0443\u043b\u0441\u044f \u0441 Docker Hub, \u0430 \u0447\u0435\u0440\u0435\u0437 Compose \u0432\u0435\u0441\u044c \u0441\u0442\u0435\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043b\u0441\u044f \u0437\u0430 \u0441\u0435\u043a\u0443\u043d\u0434\u044b.<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c \u0432\u0430\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Dockerfile \u2014 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u0441\u0431\u043e\u0440\u043a\u0435 \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u0440\u0438\u0447\u0451\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0447\u0430\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u044b\u0435 \u0441\u043b\u043e\u0438 \u0431\u044b\u043b\u0438 \u043d\u0438\u0436\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435: \u0442\u043e\u0433\u0434\u0430 Docker \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u044d\u0448 \u0434\u043b\u044f \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u0438\u0432\u0448\u0438\u0445\u0441\u044f \u0441\u043b\u043e\u0451\u0432 \u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u0434\u0430.<\/p>\n<hr\/>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u044f \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043b \u0418\u0418\u0448\u043a\u0443 \u0432\u044b\u043f\u043b\u044e\u043d\u0443\u0442\u044c \u043c\u043d\u0435 README \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u0434\u0440\u0443\u0433\u0430\u044f \u0418\u0418\u0448\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u043b\u0430 \u0447\u0438\u0441\u0442\u044b\u0439 \u0444\u0440\u043e\u043d\u0442. \u042f \u0434\u0430\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 Manus \u2014 \u044d\u0442\u043e \u0430\u0433\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0438\u043b\u0438\u0442\u044c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043d\u0443\u043b\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u044f \u0442\u0440\u0438 \u0440\u0430\u0437\u0430 \u0441 \u043d\u0443\u043b\u044f \u043f\u0440\u043e\u0441\u0438\u043b \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u043e\u043d\u0442. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u0436\u0435 \u043d\u0435 \u043c\u043e\u0433 \u0442\u043e\u043b\u043a\u043e\u043c \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0435 \u0442\u0430\u043a.<\/p>\n<p>\u041e\u0442\u0431\u0440\u043e\u0441\u0438\u0432 \u0432\u0435\u0441\u044c \u0433\u043e\u0432\u043d\u043e\u043a\u043e\u0434 \u043e\u0442 Manus (\u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u044b \u0449\u0435\u0434\u0440\u043e \u043d\u0430\u0432\u0430\u043b\u0438\u0432\u0430\u044e\u0442 \u0440\u044f\u0434\u043e\u043c \u043a\u0443\u0447\u0443&#8230; \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0431\u044f), \u044f \u043d\u0430\u0447\u0430\u043b \u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u043e\u043d\u0442 \u0441 Claude \u0441 \u043d\u0443\u043b\u044f \u2014 \u043f\u0440\u0438\u0447\u0451\u043c \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430. \u0422\u0430\u043a \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441\u00a0<strong>Vite<\/strong>\u00a0\u2014 \u0431\u0430\u043d\u0434\u043b\u0435\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437 TS, TSX \u0438 \u043f\u0440\u043e\u0447\u0435\u0433\u043e \u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c: \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043e\u0442\u0434\u0430\u0451\u0442 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0443\u044e HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443.<\/p>\n<p>\u0422\u0443\u0442 \u0442\u0430\u043a \u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c \u043e\u0434\u043d\u0443 \u0434\u0435\u043b\u0430\u043b\u044c &#8212; \u0418\u0418\u0448\u043a\u0438 \u0442\u0443\u043f\u044b\u0435. \u0412 \u043f\u043b\u0430\u043d\u0435 \u043e\u043d\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043d\u043e\u044e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u0418\u0418. <\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u044f \u043f\u0440\u043e\u0448\u0443 \u0418\u0418 \u043d\u0430\u043a\u0430\u0442\u0430\u0442\u044c \u043c\u043d\u0435 \u043d\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 &#8212; \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u043e-\u043f\u0440\u043e\u043c\u043f\u0442 \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0418\u0418, \u0447\u0442\u043e\u0431\u044b \u0412\u0415\u0421\u042c \u0442\u0435\u043a\u0441\u0442 &#8212; \u0448\u0440\u0438\u0444\u0442\u044b, \u043e\u0442\u0441\u0442\u0443\u043f\u044b, \u0446\u0432\u0435\u0442\u0430, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b &#8212; \u0438\u043c\u0435\u043b\u0438 \u041e\u0414\u0418\u041d \u0418 \u0422\u041e\u0422 \u0416\u0415 \u0441\u0442\u0438\u043b\u044c. <\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cf5\/1cb\/0fb\/cf51cb0fba8bc80b142a7bbf8f611ec5.png\" alt=\" \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0438\u043f\u043e\u0433\u0440\u0430\u0444\u0438\u043a\u0430\" title=\" \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0438\u043f\u043e\u0433\u0440\u0430\u0444\u0438\u043a\u0430\" width=\"2940\" height=\"1840\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/cf5\/1cb\/0fb\/cf51cb0fba8bc80b142a7bbf8f611ec5.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cf5\/1cb\/0fb\/cf51cb0fba8bc80b142a7bbf8f611ec5.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption> \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0438\u043f\u043e\u0433\u0440\u0430\u0444\u0438\u043a\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 &#8212; \u044d\u0442\u043e \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043f\u0430\u043f\u043a\u0435 <code>cStyles<\/code> \u043b\u0435\u0436\u0430\u0442 <code>*Stls.ts<\/code> \u0444\u0430\u0439\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/p>\n<pre><code>src\/styles\/\u251c\u2500\u2500 tokens.ts        \u2014 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0435 \u0442\u043e\u043a\u0435\u043d\u044b (typography, surface, radius, \u2026)\u251c\u2500\u2500 animations.ts    \u2014 transition, hover, press, enter, loading\u251c\u2500\u2500 variants.ts      \u2014 colorScheme + \u0442\u0438\u043f ColorScheme\u251c\u2500\u2500 index.ts         \u2014 \u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430, \u0440\u0435\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0451\u2514\u2500\u2500 cStyles\/         \u2014 \u0441\u0442\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0440\u0430\u0437\u0431\u0438\u0442\u044b\u0435 \u043f\u043e \u043f\u0430\u043f\u043a\u0430\u043c src\/components\/    \u251c\u2500\u2500 uiStls.ts        \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/ui\/    \u251c\u2500\u2500 commonStls.ts    \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/common\/    \u251c\u2500\u2500 layoutStls.ts    \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/layout\/    \u251c\u2500\u2500 dashboardStls.ts \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/dashboard\/    \u251c\u2500\u2500 usersStls.ts     \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/users\/    \u251c\u2500\u2500 serversStls.ts   \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/servers\/    \u2514\u2500\u2500 pagesStls.ts     \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 pages\/<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0435 \u0431\u044b\u043b\u043e. \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 \u0445\u0430\u043e\u0442\u0438\u0447\u043d\u044b\u043c\u0438. \u0413\u0434\u0435 \u0442\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u043b\u0441\u044f \u0440\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u043e\u0432, \u0433\u0434\u0435-\u0442\u043e \u0446\u0432\u0435\u0442\u0430. \u0422\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043d\u0430 \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u2014 \u044d\u0442\u043e md \u0444\u0430\u0439\u043b \u043d\u0430 250+ \u0441\u0442\u0440\u043e\u043a.<\/p>\n<hr\/>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0418\u0418 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043d\u044b\u0445: Claude, Grok, Gemini, ChatGPT, Codex. \u041d\u0435 \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b \u043d\u0438 \u0446\u0435\u043d\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 15 Google-\u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u0432, \u0438 \u043b\u0438\u043c\u0438\u0442\u043e\u0432 \u043d\u0430 \u0432\u0435\u0441\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0434\u0435\u043d\u044c \u0445\u0432\u0430\u0442\u0430\u043b\u043e \u0441 \u0437\u0430\u043f\u0430\u0441\u043e\u043c.<\/p>\n<p>\u0428\u0442\u0443\u043a\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0418\u0418 \u0432\u0430\u0436\u0435\u043d \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u2014 \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b, \u0447\u0442\u043e \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0<code>.env<\/code>, \u043a\u0430\u043a \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f \u2014 \u0431\u043e\u043b\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0447\u0430\u043b \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0447\u0435\u0440\u0435\u0437\u00a0<code>tar<\/code>\u00a0\u0438 \u0441\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0432 \u0432 \u0447\u0430\u0442. \u0415\u0441\u043b\u0438 \u0444\u0438\u0447\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0430 \u0431\u041e\u043b\u044c\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u0436\u0438\u0433\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b \u0432\u043f\u0443\u0441\u0442\u0443\u044e.<\/p>\n<p>\u041d\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0440\u0443\u043a\u0430\u043c\u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u2014\u00a0<code>.git<\/code>,\u00a0<code>venv<\/code>,\u00a0<code>node_modules<\/code>,\u00a0<code>dist<\/code>\u00a0\u0438 \u043f\u0440\u043e\u0447\u0438\u0439 \u043c\u0443\u0441\u043e\u0440 \u2014 \u0442\u0430\u043a\u043e\u0435 \u0441\u0435\u0431\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043b bash-\u0441\u043a\u0440\u0438\u043f\u0442\u00a0<code>pack.sh<\/code>. \u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b:<\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash## \u0421\u043a\u0440\u0438\u043f\u0442 pack \u2014 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0430 \u0447\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 htrBox \u0432 .tar \u0430\u0440\u0445\u0438\u0432\u044b# \u0412\u0441\u0435 \u0430\u0440\u0445\u0438\u0432\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\/Users\/stas\/projects\/)## \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435:#   pack          -&gt; \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u043a\u0440\u043e\u043c\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439)#   pack back     -&gt; backend + docker-compose.yaml + .env#   pack front    -&gt; frontend + docker-compose.yaml + .env#   pack --dry-run [all|back|front]  -&gt; \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 tar, \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c#set -euo pipefail# ------------------------------------------------#          \u0416\u0401\u0421\u0422\u041a\u041e \u0417\u0410\u0425\u0410\u0420\u0414\u041a\u041e\u0416\u0415\u041d\u041d\u042b\u0415 \u041f\u0423\u0422\u0418# ------------------------------------------------readonly PROJECT_ROOT=\"\/Users\/stas\/projects\/htrBox\"readonly OUTPUT_DIR=\"$(dirname \"$PROJECT_ROOT\")\"   # -&gt; \/Users\/stas\/projectsreadonly PROJECT_NAME=\"htrBox\"# ------------------------------------------------#     \u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 (\u043f\u0440\u0438 pack \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432)# ------------------------------------------------declare -a EXCLUDES=(    \".git\"    \".env\"    \"backend\/venv\"    \"backend\/.DS_Store\"    \"frontend\/node_modules\"    \"frontend\/.DS_Store\"    \"frontend\/package-lock.json\"    \".DS_Store\"    \"other\"    \"exclude.txt\")\u0438 \u0442\u0434 ...<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<p>\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0442\u0440\u044e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u0420\u0430\u043d\u044c\u0448\u0435 \u044f \u0441\u0440\u0430\u0437\u0443 \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u0418\u0418: \u00ab\u0434\u0430\u0432\u0430\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0444\u0438\u0447\u0443\u00bb. \u0422\u0435\u043f\u0435\u0440\u044c \u2014 \u043d\u0435\u0442. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u043e\u0432\u043e\u0440\u044e:\u00a0<strong>\u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0439 \u043a\u043e\u0434<\/strong>. \u041e\u043f\u0438\u0448\u0438 \u043f\u043b\u0430\u043d \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0444\u0438\u0447\u0438 \u0441 TODO-\u043c\u0430\u0440\u043a\u0435\u0440\u0430\u043c\u0438 \u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u2014 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0432 \u0442\u0435\u043c\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u043d\u044f\u043b \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c. \u041c\u044b \u043e\u0431\u043a\u0430\u0448\u043b\u0438\u0432\u0430\u043b\u0438 \u043f\u043b\u0430\u043d, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u044f \u0434\u0430\u0432\u0430\u043b \u043a\u043e\u043c\u0430\u043d\u0434\u0443: \u0432\u043f\u0435\u0440\u0451\u0434, \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430.<\/p>\n<p>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043f\u0440\u043e\u0441\u0438\u043b \u0418\u0418 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c\u00a0<strong>\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/strong>\u00a0\u2014 \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d\u043d\u044b\u0439 TODO \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u043e\u043c \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430. \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0444\u0430\u0439\u043b\u044b, \u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0447\u0435\u0440\u0435\u0437\u00a0<code>git dif<\/code>\u00a0 \u0432 VSCode, \u0447\u0442\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u043a \u2014 \u0434\u0432\u0438\u0433\u0430\u043b\u0438\u0441\u044c \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p>\u041a\u0441\u0442\u0430\u0442\u0438, GitKraken \u2014 \u0442\u043e\u043f. \u0420\u0430\u043d\u044c\u0448\u0435 \u0441\u0438\u0434\u0435\u043b \u043d\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u00a0<code>tig<\/code>, \u043d\u043e GitKraken \u0443\u0434\u043e\u0431\u043d\u0435\u0435, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0435\u0442\u043e\u043a. \u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u2014 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \ud83d\ude42<\/p>\n<p>\u0422\u0430\u043a \u0432 \u0447\u0451\u043c \u043a\u0430\u0439\u0444 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430? \u041a\u043e\u0433\u0434\u0430 \u0418\u0418 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0433\u0430\u043b\u043b\u044e\u0446\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d\u044b \u043d\u0430 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0435 \u2014 \u043d\u0435 \u0441\u0442\u0440\u0430\u0448\u043d\u043e. \u041c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c\u00a0<code>.\/pack.sh<\/code>, \u043f\u0435\u0440\u0435\u043a\u0438\u043d\u0443\u0442\u044c \u0430\u0440\u0445\u0438\u0432 \u0441 \u0430\u043a\u0442\u0443\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 TODO, \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u0433\u0434\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f.<\/p>\n<p>\u042f \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0445\u043e\u0434 \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u0434 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f Claude, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 <code>tar<\/code> \u0430\u0440\u0445\u0438\u0432\u0430\u043c\u0438 (\u043a\u0430\u043a \u0438 Manus). <\/p>\n<hr\/>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0432 \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u0444\u0440\u043e\u043d\u0442\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0432\u0441\u044e \u044d\u0442\u0443 \u0448\u0430\u0440\u043c\u0430\u043d\u043a\u0443, \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043a\u0443\u0447\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u0411\u044d\u043a\u0435\u043d\u0434 \u0435\u0441\u0442\u044c, \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u2014 \u043d\u043e \u043a\u0430\u043a \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u043e \u0444\u0440\u043e\u043d\u0442\u0430? \u041f\u0440\u0438\u0447\u0451\u043c \u043d\u0435 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e. \u041a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0432\u0445\u043e\u0434? \u041a\u0430\u043a \u043d\u0435 \u0434\u043e\u043b\u0431\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043b\u0438\u0448\u043d\u0438\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435? \u0412\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u044b\u043b\u043e \u043c\u043d\u043e\u0433\u043e.<\/p>\n<p>\u041d\u0430\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u0441 \u0418\u0418, \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439 DOM-\u0434\u0435\u0440\u0435\u0432\u0430 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u043b \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0441\u0442\u0435\u043a:<\/p>\n<ul>\n<li>\n<p><strong>TanStack Query<\/strong>\u00a0\u2014 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435<\/p>\n<\/li>\n<li>\n<p><strong>Zustand + localStorage<\/strong>\u00a0\u2014 \u0434\u043b\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0441\u0441\u0438\u044f\u043c\u0438<\/p>\n<\/li>\n<li>\n<p><strong>wouter<\/strong>\u00a0\u2014 \u043b\u0451\u0433\u043a\u0438\u0439 \u0440\u043e\u0443\u0442\u0435\u0440 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0449\u0435 React Router<\/p>\n<\/li>\n<li>\n<p><strong>httpOnly cookie<\/strong>\u00a0\u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f refresh token; \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0431\u044d\u043a\u0435\u043d\u0434\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u043e\u043d\u0443\u0442\u044c \u0432 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u0434\u0435\u043b\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 <a href=\"https:\/\/github.com\/extekky\/miniLearn\" rel=\"noopener noreferrer nofollow\">\u043c\u0438\u043d\u0438-\u043f\u0440\u043e\u0435\u043a\u0442<\/a> \u2014 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u0447\u0435\u0440\u0435\u0437 TanStack Query \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Zustand + cookie. \u041d\u0443 \u0438 \u0437\u0430\u043e\u0434\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0441\u044f, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<p>\u0415\u0449\u0451 \u043e\u0442\u043a\u0440\u044b\u043b \u0434\u043b\u044f \u0441\u0435\u0431\u044f\u00a0<strong>Postman<\/strong>. \u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c API \u2014 \u043a\u0430\u0439\u0444. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u043d\u0430\u044f \u0444\u0438\u0447\u0430 \u2014 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437: \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c pre- \u0438 post-scripts \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043f\u0440\u0430\u0432\u0434\u0430 \u0431\u0438\u043b\u0441\u044f 3 \u0447\u0430\u0441\u0430 \u043f\u043e\u0447\u0435\u043c\u0443 postman \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 cookie &#8212; \u043d\u0430\u0434\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0443\u043c\u0431\u043b\u0435\u0440 Cookie Jar \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0432 OFF). <\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d24\/c5e\/3d8\/d24c5e3d849f1f0004f637d0a7f87753.png\" alt=\"postman moooood\" title=\"postman moooood\" width=\"2940\" height=\"1840\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/d24\/c5e\/3d8\/d24c5e3d849f1f0004f637d0a7f87753.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d24\/c5e\/3d8\/d24c5e3d849f1f0004f637d0a7f87753.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>postman moooood<\/figcaption><\/div>\n<\/figure>\n<hr\/>\n<p>\u0420\u0430\u0437\u043e\u0431\u0440\u0430\u0432\u0448\u0438\u0441\u044c \u0432 \u043c\u0438\u043d\u0438-\u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u044d\u0442\u0438 \u0434\u0432\u0430 \u0431\u0440\u0430\u0442\u0430 \u2014 frontend \u0438 backend, \u2014 \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0433\u043b\u0430\u0432\u044b: \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0431\u044b\u043b\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430. \u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 foreign key \u0438\u043b\u0438 primary key \u2014 \u0437\u0430\u0433\u0430\u0434\u043a\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043a\u0430\u0447\u0430\u043b\u00a0<strong>DataGrip<\/strong>, \u0441\u0434\u0435\u043b\u0430\u043b \u0434\u0430\u043c\u043f \u0431\u0430\u0437\u044b \u0441 \u043f\u0440\u043e\u0434\u0430 \u0438 \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f. PostgreSQL \u0443\u0436\u0435 \u043a\u0440\u0443\u0442\u0438\u043b\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0434\u0435, \u043d\u043e \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u2014 \u0431\u044b\u043b\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e. \u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0434\u0435\u043b\u0430\u043b <a href=\"https:\/\/github.com\/extekky\/dblabs#\" rel=\"noopener noreferrer nofollow\">\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u0443 \u0434\u043b\u044f \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0442 \u043f\u043e SQL \u043d\u0430 \u0431\u0430\u0437\u0435 PostgreSQL 17 \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435<\/a>.<\/p>\n<p>\u041d\u0430\u0448\u0451\u043b \u043a\u043b\u0430\u0441\u0441\u043d\u044b\u0439 \u043a\u0443\u0440\u0441 \u043e\u0442 Postgres Pro \u0438 \u0438\u0445 \u0436\u0435 \u043a\u043d\u0438\u0433\u0443 \u043f\u043e SQL, \u0433\u0434\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438: \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043a\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c DDL. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0442\u0430\u043b\u0430 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438\u0448\u043b\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0418\u0418\u0448\u043a\u0430 \u043d\u0435 \u0432\u0441\u0435 \u0441\u0432\u044f\u0437\u0438 \u043c\u0435\u0436\u0434\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438 \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u043b\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b\u0442\u044c <em>\u0432\u0438\u0441\u044f\u0447\u0438\u0435<\/em> \u0434\u0430\u043d\u043d\u044b\u0435 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u0430\u043b\u044f\u0442\u044c\u0441\u044f \u043d\u0430 ON DELETE CASCADE).<\/p>\n<hr\/>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u044b\u043c \u0445\u043e\u0434\u043e\u043c. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0412\u0421\u0422\u0410\u041b \u0432\u043e\u043f\u0440\u043e\u0441 \u043e\u0431 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0435\u043f\u043b\u043e\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0422\u0430\u043a\u043e\u0435 \u0442\u0443\u0442 \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c. Bash \u0441\u043a\u0440\u0438\u043f\u0442. \u0421\u043a\u0440\u0438\u043f\u0442 \u043d\u0430\u043a\u0430\u0442\u044b\u0432\u0430\u0435\u0442 docker container Hysteria2 \u043d\u0430 \u043d\u043e\u0434\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0442\u0440\u0430\u043d\u0430\u0445 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c) \u0438 \u043d\u0430 backend \u0432 Yandex Cloud. \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u0435\u043f\u043b\u043e\u044f \u043d\u0430 YC \u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0440\u043e\u0434\u043b\u0435\u043d\u0438\u0435\u043c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 certbot:<\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ccf\/245\/d4a\/ccf245d4a9bda809a367968cb81b0681.png\" alt=\"\u0441\u043a\u0440\u0438\u043d admin dashboard\" title=\"\u0441\u043a\u0440\u0438\u043d admin dashboard\" width=\"2940\" height=\"1840\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/ccf\/245\/d4a\/ccf245d4a9bda809a367968cb81b0681.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ccf\/245\/d4a\/ccf245d4a9bda809a367968cb81b0681.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0441\u043a\u0440\u0438\u043d admin dashboard<\/figcaption><\/div>\n<\/figure>\n<pre><code class=\"bash\"># ----------------------------------------------------# \u0414\u0415\u041f\u041b\u041e\u0419 Yandex Cloud (frontend + backend + postgres)# ----------------------------------------------------deploy_yc() {  echo \"\"  echo \"-------------------------------------------\"  echo \"  \ud83d\ude80 \u0414\u0435\u043f\u043b\u043e\u0439 -&gt; Yandex Cloud ($YC_HOST)\"  echo \"-------------------------------------------\"  [ ! -f \"$SCRIPT_DIR\/certificates\/yandex-cloud.ini\" ] &amp;&amp; fail \"certificates\/yandex-cloud.ini \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\"  [ ! -f \"$SCRIPT_DIR\/infra\/.env\" ]                    &amp;&amp; fail \"infra\/.env \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\"  [ ! -f \"$SCRIPT_DIR\/infra\/nginx.conf\" ]              &amp;&amp; fail \"infra\/nginx.conf \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\"  log \"\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043d\u0430 YC...\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"mkdir -p $YC_DIR $YC_DATA_DIR\/pgdata\"  log \"\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c backend\/ \u043d\u0430 YC...\"  tar -czf \/tmp\/backend.tar.gz \\    --exclude=\"venv\" \\    --exclude=\"__pycache__\" \\    --exclude=\"*.pyc\" \\    --exclude=\"pytest.ini\" \\    --exclude=\".pytest_cache\" \\    --exclude=\"requirements-dev.txt\" \\    --exclude=\"TODO\" \\    -C \"$PROJECT_ROOT\" backend  scp -i \"$YC_KEY\" \/tmp\/backend.tar.gz \"$YC_USER@$YC_HOST:\/tmp\/\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"tar --warning=no-unknown-keyword -xzf \/tmp\/backend.tar.gz -C $YC_DIR &amp;&amp; rm \/tmp\/backend.tar.gz\"  rm \/tmp\/backend.tar.gz  log \"\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c frontend\/ \u043d\u0430 YC...\"  tar -czf \/tmp\/frontend.tar.gz \\    --exclude=\"node_modules\" \\    --exclude=\"dist\" \\    --exclude=\"TODO\" \\    --exclude=\"nginx.conf\" \\    -C \"$PROJECT_ROOT\" frontend  scp -i \"$YC_KEY\" \/tmp\/frontend.tar.gz \"$YC_USER@$YC_HOST:\/tmp\/\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"tar --warning=no-unknown-keyword -xzf \/tmp\/frontend.tar.gz -C $YC_DIR &amp;&amp; rm \/tmp\/frontend.tar.gz\"  rm \/tmp\/frontend.tar.gz  # nginx.conf \u0434\u043b\u044f prod \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u043f\u043e\u0432\u0435\u0440\u0445 \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e frontend\/  # dev-\u0444\u0430\u0439\u043b (frontend\/nginx.conf \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438) \u043d\u0435 \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u0442\u0441\u044f  log \"\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c prod nginx.conf \u043d\u0430 YC (infra\/nginx.conf -&gt; frontend\/nginx.conf)...\"  scp -i \"$YC_KEY\" \"$SCRIPT_DIR\/infra\/nginx.conf\" \"$YC_USER@$YC_HOST:$YC_DIR\/frontend\/nginx.conf\"  log \"\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c docker-compose \u0438 .env...\"  scp -i \"$YC_KEY\" \"$SCRIPT_DIR\/infra\/docker-compose.yaml\" \"$YC_USER@$YC_HOST:$YC_DIR\/docker-compose.yaml\"  scp -i \"$YC_KEY\" \"$SCRIPT_DIR\/infra\/.env\"                \"$YC_USER@$YC_HOST:$YC_DIR\/.env\"  log \"\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c Cloudflare \u0442\u043e\u043a\u0435\u043d...\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"mkdir -p ~\/.secrets &amp;&amp; chmod 700 ~\/.secrets\"  scp -i \"$YC_KEY\" \"$SCRIPT_DIR\/certificates\/yandex-cloud.ini\" \"$YC_USER@$YC_HOST:~\/.secrets\/cloudflare-yc.ini\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"chmod 600 ~\/.secrets\/cloudflare-yc.ini\"  log \"\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0434\u043b\u044f stdoq.ru...\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" '    CERT_PATH=\"\/etc\/letsencrypt\/live\/stdoq.ru\/fullchain.pem\"    RENEW_NEEDED=false    if [ ! -f \"$CERT_PATH\" ]; then      echo \"  -&gt; \u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439...\"      RENEW_NEEDED=true    else      EXPIRY=$(openssl x509 -enddate -noout -in \"$CERT_PATH\" | cut -d= -f2)      EXPIRY_TS=$(date -d \"$EXPIRY\" +%s 2&gt;\/dev\/null || date -j -f \"%b %d %T %Y %Z\" \"$EXPIRY\" +%s 2&gt;\/dev\/null)      NOW_TS=$(date +%s)      DAYS_LEFT=$(( (EXPIRY_TS - NOW_TS) \/ 86400 ))      echo \"  -&gt; \u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u043d\u0430\u0439\u0434\u0435\u043d, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0434\u043d\u0435\u0439: $DAYS_LEFT\"      [ \"$DAYS_LEFT\" -lt 30 ] &amp;&amp; RENEW_NEEDED=true    fi    if [ \"$RENEW_NEEDED\" = true ]; then      if ! command -v certbot &amp;&gt;\/dev\/null; then        echo \"  -&gt; \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c certbot...\"        sudo apt-get update -qq &amp;&amp; sudo apt-get install -y -qq certbot python3-certbot-dns-cloudflare      fi      sudo certbot certonly \\        --dns-cloudflare \\        --dns-cloudflare-credentials ~\/.secrets\/cloudflare-yc.ini \\        -d stdoq.ru -d www.stdoq.ru \\        --email \u0422\u0423\u0422 \u0411\u042b\u041b \u041c\u041e\u0419 EMAIL@yandex.ru \\        --agree-tos --no-eff-email \\        --non-interactive      echo \"  -&gt; \u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u2713\"    else      echo \"  -&gt; \u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u0435\u043d, \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u2713\"    fi  '  log \"\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b (--build)...\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"    cd $YC_DIR    docker compose -f docker-compose.yaml up -d --build --force-recreate frontend backend postgres    docker image prune -f  \"  echo \"\"  echo \"---- \u0421\u0442\u0430\u0442\u0443\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 ----\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"docker ps --filter name=frontend --filter name=backend --filter name=postgres --format 'table {{.Names}}\\t{{.Status}}\\t{{.Ports}}'\"  echo \"\"  echo \"---- \u041b\u043e\u0433\u0438 backend (\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 20 \u0441\u0442\u0440\u043e\u043a) ----\"  ssh -i \"$YC_KEY\" \"$YC_USER@$YC_HOST\" \"docker logs backend --tail=20\"  log \"Yandex Cloud \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d \u2713\"}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0413\u0434\u0435 Ansible? \u0413\u0434\u0435 Terraform? \u0414\u043b\u044f \u0442\u0440\u0435\u0445 \u0438\u043b\u0438 \u043f\u044f\u0442\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e \u043a\u0443\u043f\u0438\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u0445 \u0440\u0443\u0447\u043a\u0430\u043c\u0438. \u041f\u044b\u0442\u0430\u043b\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c bash \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0434\u043b\u044f deploy \u0438 cleanup (\u043e\u043d \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c) \u043d\u0430 Ansible PlayBooks, \u043d\u043e \u043f\u043e\u0432\u044f\u0437 \u0432 \u044d\u0442\u043e\u043c. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043b\u0438\u0448\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e playbook&#8217;a) \u0438\u0445 \u0437\u0430\u043a\u043e\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 bash \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f &#8212; \u0440\u0435\u0448\u0438\u043b \u044f.<\/p>\n<hr\/>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043d\u043e\u0432, \u043a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442:<\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 backend \u0441\u0442\u0440\u0435\u043b\u044f\u0435\u0442 \u0432\u0441\u0435\u043c \u043f\u0443\u043b\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441\u0442\u0430\u043d\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 100 (\u0447\u0442\u043e \u044f \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e), \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e. \u0422\u043e\u0433\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0442\u0435\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e 50 \u0447\u0435\u043b\u043e\u0432\u0435\u043a. <\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fd9\/e08\/433\/fd9e084332b81ba7d43640400af2d396.png\" alt=\"\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u044e\u0437\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 \" title=\"\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u044e\u0437\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 \" width=\"2940\" height=\"1840\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/fd9\/e08\/433\/fd9e084332b81ba7d43640400af2d396.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fd9\/e08\/433\/fd9e084332b81ba7d43640400af2d396.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u044e\u0437\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 <\/figcaption><\/div>\n<\/figure>\n<p>\u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0437\u0432\u0435\u0440\u0443\u0448\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442\u0441\u044f \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044e\u0437\u0435\u0440\u043d\u0435\u0439\u043c\u0430 \u043f\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443 <code>djb2<\/code>. \u0418\u0445 12 \u0448\u0442\u0443\u043a, \u0432\u0441\u0435 SVG.<\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0d0\/57c\/817\/0d057c817999fdcd87d89eef519a51cb.png\" alt=\"\u043b\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\" title=\"\u043b\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\" width=\"2940\" height=\"1840\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/0d0\/57c\/817\/0d057c817999fdcd87d89eef519a51cb.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0d0\/57c\/817\/0d057c817999fdcd87d89eef519a51cb.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u043b\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439<\/figcaption><\/div>\n<\/figure>\n<hr\/>\n<p>\u0418 \u0432\u043e\u0442 \u044f \u0442\u0443\u0442 \ud83d\ude42\u2014 21 \u043c\u0430\u044f 26 \u0433\u043e\u0434\u0430 \u2014 \u0445\u043e\u0447\u0443 \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u044b\u0439 \u0448\u043b\u044e\u0437. API \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e, \u043d\u043e \u043d\u0438\u043a\u0442\u043e \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0434\u043e\u0431\u0440\u0438\u043b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u041a\u0442\u043e \u0437\u043d\u0430\u0435\u0442 \u043a\u0430\u043a\u0438\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043b\u0430\u0442\u0435\u0436\u043d\u044b\u0435 \u0448\u043b\u044e\u0437\u044b \u0434\u043b\u044f high risk \u0431\u0435\u0437 \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f \u0441\u0437\/\u0438\u043f \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u043d\u0435\u043d\u0443\u0436\u043d\u043e\u0441\u0442\u0435\u0439? \u0416\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u0435\u0437 \u043a\u043e\u043d\u0441\u043a\u0438\u0445 \u043a\u043e\u043c\u0438\u0441\u0441\u0438\u0439, \u0434\u043e\u043a\u043e\u0439 API \u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0435\u043c Sandbox.<\/p>\n<p>\u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c Prometheus \u0441 Grafana, Node Exporter \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u0440\u0438\u043a \u043d\u043e\u0434 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0445 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043a\u0430\u043a \u0431\u0438\u0437\u043d\u0435\u0441 \u0444\u0438\u0447\u0430.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1037922\/\">https:\/\/habr.com\/ru\/articles\/1037922\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u0425\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0442\u0435\u043c, \u043a\u0430\u043a \u044f, \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0431\u0435\u0437 \u043d\u0430\u0432\u044b\u043a\u043e\u0432 fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0441\u0434\u0435\u043b\u0430\u043b, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u044b\u0439 SaaS. \u0412\u0435\u0441\u044c \u0442\u0435\u043a\u0441\u0442 &#8212; \u043c\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u043c\u044b\u0441\u043b\u0435\u0439 \u0438 \u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439. \u041c\u043e\u0451 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e: MacBook Air M2, 16 \u0413\u0411. \u0423 \u043c\u0435\u043d\u044f \u043d\u0435\u0442 \u043e\u043f\u044b\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0431\u0438\u0433\u0442\u0435\u0445\u0435, \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0432 \u043a\u0430\u043a\u043e\u043c \u043b\u0438\u0431\u043e \u0442\u0435\u0445\u0435, \u0445\u0435\u0445\u0435 \ud83d\ude42\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 2025 \u0433\u043e\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0435\u0445\u0430\u043b \u0432 \u0433\u043e\u0441\u0442\u0438 \u043a \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0430\u0437\u0434\u043d\u043e\u0432\u0430\u0442\u044c \u041d\u043e\u0432\u044b\u0439 \u0433\u043e\u0434, \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043d\u0435\u0431\u044b\u0432\u0430\u043b\u043e\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u2014 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443. ChatGPT, Grok, Claude, YouTube, Telegram \u2014 \u0432\u0441\u0451. \u041c\u043e\u0439 \u0440\u043e\u0434\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u043e\u043d \u0431\u044b\u043b \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0430 \u043a\u043e\u043c \u0420\u041a\u041d \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0431\u0435\u043b\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438.\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a OpenVPN \u2014 \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u044b \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043b\u0438 \u043a\u043b\u044e\u0447\u0438 \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f. \u0414\u0430, \u0441 \u043c\u043e\u0435\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0436\u0435\u043d\u0438\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\u044e. \u041d\u043e \u043c\u0435\u043d\u044f \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u043e, \u043f\u043e\u043a\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 2025 \u0433\u043e\u0434\u0430 OpenVPN \u043d\u0435 \u0437\u0430\u0431\u0430\u043d\u0438\u043b\u0438. \u041c\u043e\u0439 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u043b \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u043a \u0441\u0432\u043e\u0435\u0439 \u0441\u0435\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e, \u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0441\u0435\u0442 \u043b\u0430\u043f\u0443.  \u042f \u043d\u0435 \u0433\u043e\u0442\u043e\u0432 \u043c\u0438\u0440\u0438\u0442\u044c\u0441\u044f \u0441 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430\u043c\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432\u0441\u0451 \u0435\u0449\u0451 \u0432 \u0440\u0435\u0433\u0438\u043e\u043d\u0435, \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430\u00a0\u043d\u0435\u0433\u043e\u00a0\u2014 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0Hysteria2. \u0411\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b VPS, \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0438 \u0431\u044b\u043b \u0440\u0430\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044e \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043c\u0438\u0440.\u041d\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u043e\u043a\u0438 \u043c\u0435\u043d\u044f \u0437\u0430\u0446\u0435\u043f\u0438\u043b\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041f\u043e \u0441\u0443\u0442\u0438 \u2014 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u0443\u0434\u043e\u0431\u043d\u043e \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u0432\u0430\u043b \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 API.\u0412 \u043a\u043e\u043d\u0446\u0435 \u0444\u0435\u0432\u0440\u0430\u043b\u044f 2026 \u0433\u043e\u0434\u0430 \u043c\u043d\u0435 \u043f\u043e\u043f\u0430\u043b\u043e\u0441\u044c \u0432\u0438\u0434\u0435\u043e \u043d\u0430 YouTube \u2014\u00a0\u00ab\u041a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043e\u043f\u043b\u0430\u0442\u0430 \u043a\u0430\u0440\u0442\u043e\u0439\u00bb. \u042d\u0442\u043e \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e \u043c\u043d\u0435, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 REST API, \u0438 \u0434\u0430\u043b\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u0438\u0435: \u0438\u0437 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0435. \u041c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0447\u0442\u043e \u044f \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c MacBook \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u044b\u043b \u0433\u043e\u0442\u043e\u0432 \u043f\u043e\u0434\u0451\u0440\u0433\u0430\u0442\u044c \u0435\u0433\u043e \u0437\u0430 \u0440\u0443\u0447\u043a\u0438.\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u0443\u0440\u043b\u0430\u043c\u0438, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u043b\u0430 \u043c\u044b\u0441\u043b\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 Python. \u041f\u0435\u0440\u0432\u043e\u0435, \u0441 \u0447\u0435\u043c \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u00a0requests.\u0421 \u0438\u0438\u0448\u043a\u043e\u0439 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u043d\u0430\u043a\u0430\u0442\u0430\u043b\u0438 \u043a\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043d\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u0412\u043e\u0442 \u043a\u0443\u0441\u043e\u0447\u0435\u043a:API_HOST   = &#171;127.0.0.1&#187;API_PORT   = 8080API_SECRET = &#171;sixseven&#187;USERS = {    &#171;s&#187;   : &#171;ss&#187;,    &#171;user&#187;: &#171;password&#187;,    &#171;test&#187;: &#171;12345&#187;,}ALLOWED = {    &#171;s&#187;   : False,    &#171;user&#187;: True,    &#171;test&#187;: False,}def get_online_users():    url = f&#187;http:\/\/{API_HOST}:{API_PORT}\/online&#187;    headers = {&#171;Authorization&#187;: API_SECRET}    try:        r = requests.get(url, headers=headers, timeout=5)        r.raise_for_status()           # \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0435\u0441\u043b\u0438 \u043d\u0435 200        return r.json()                # {&#171;username&#187;: connection_count, &#8230;}    except requests.exceptions.HTTPError as e:        print(f&#187;API \u0432\u0435\u0440\u043d\u0443\u043b \u043e\u0448\u0438\u0431\u043a\u0443 {r.status_code}: {r.text}&#187;)        return {}    except requests.exceptions.RequestException as e:        print(f&#187;\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a API: {e}&#187;)        return {}\u041d\u0435 \u0431\u0443\u0434\u0443 \u0432\u0440\u0430\u0442\u044c, \u043d\u0430 \u043d\u043e\u0432\u0438\u0447\u043a\u0430 \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0432\u043e\u0441\u0445\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u044d\u0442\u0438\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 VPN-\u0441\u0435\u0440\u0432\u0438\u0441. \u0418\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u0441\u0442\u0432\u043e.\u041d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430. \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u043b \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u0442\u0440\u0438 \u0447\u0430\u0441\u0442\u0438: backend, frontend, Hysteria2 \u2014 \u0442\u0440\u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0437\u043e\u043d\u044b \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f. \u0422\u0430\u043a \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441\u00a0Docker Compose. \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0434\u043b\u044f Hysteria2 \u0443\u0436\u0435 \u0442\u044f\u043d\u0443\u043b\u0441\u044f \u0441 Docker Hub, \u0430 \u0447\u0435\u0440\u0435\u0437 Compose \u0432\u0435\u0441\u044c \u0441\u0442\u0435\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043b\u0441\u044f \u0437\u0430 \u0441\u0435\u043a\u0443\u043d\u0434\u044b.\u041f\u043e\u0442\u043e\u043c \u0432\u0430\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Dockerfile \u2014 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u0441\u0431\u043e\u0440\u043a\u0435 \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u0440\u0438\u0447\u0451\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0447\u0430\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u044b\u0435 \u0441\u043b\u043e\u0438 \u0431\u044b\u043b\u0438 \u043d\u0438\u0436\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435: \u0442\u043e\u0433\u0434\u0430 Docker \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u044d\u0448 \u0434\u043b\u044f \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u0438\u0432\u0448\u0438\u0445\u0441\u044f \u0441\u043b\u043e\u0451\u0432 \u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u0434\u0430.\u0414\u0430\u043b\u044c\u0448\u0435 \u044f \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043b \u0418\u0418\u0448\u043a\u0443 \u0432\u044b\u043f\u043b\u044e\u043d\u0443\u0442\u044c \u043c\u043d\u0435 README \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u0434\u0440\u0443\u0433\u0430\u044f \u0418\u0418\u0448\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u043b\u0430 \u0447\u0438\u0441\u0442\u044b\u0439 \u0444\u0440\u043e\u043d\u0442. \u042f \u0434\u0430\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 Manus \u2014 \u044d\u0442\u043e \u0430\u0433\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0438\u043b\u0438\u0442\u044c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043d\u0443\u043b\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u044f \u0442\u0440\u0438 \u0440\u0430\u0437\u0430 \u0441 \u043d\u0443\u043b\u044f \u043f\u0440\u043e\u0441\u0438\u043b \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u043e\u043d\u0442. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u0436\u0435 \u043d\u0435 \u043c\u043e\u0433 \u0442\u043e\u043b\u043a\u043e\u043c \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0435 \u0442\u0430\u043a.\u041e\u0442\u0431\u0440\u043e\u0441\u0438\u0432 \u0432\u0435\u0441\u044c \u0433\u043e\u0432\u043d\u043e\u043a\u043e\u0434 \u043e\u0442 Manus (\u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u044b \u0449\u0435\u0434\u0440\u043e \u043d\u0430\u0432\u0430\u043b\u0438\u0432\u0430\u044e\u0442 \u0440\u044f\u0434\u043e\u043c \u043a\u0443\u0447\u0443&#8230; \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0431\u044f), \u044f \u043d\u0430\u0447\u0430\u043b \u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u043e\u043d\u0442 \u0441 Claude \u0441 \u043d\u0443\u043b\u044f \u2014 \u043f\u0440\u0438\u0447\u0451\u043c \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430. \u0422\u0430\u043a \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441\u00a0Vite\u00a0\u2014 \u0431\u0430\u043d\u0434\u043b\u0435\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437 TS, TSX \u0438 \u043f\u0440\u043e\u0447\u0435\u0433\u043e \u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c: \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043e\u0442\u0434\u0430\u0451\u0442 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0443\u044e HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443.\u0422\u0443\u0442 \u0442\u0430\u043a \u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c \u043e\u0434\u043d\u0443 \u0434\u0435\u043b\u0430\u043b\u044c &#8212; \u0418\u0418\u0448\u043a\u0438 \u0442\u0443\u043f\u044b\u0435. \u0412 \u043f\u043b\u0430\u043d\u0435 \u043e\u043d\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043d\u043e\u044e \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u0418\u0418. \u041a\u043e\u0433\u0434\u0430 \u044f \u043f\u0440\u043e\u0448\u0443 \u0418\u0418 \u043d\u0430\u043a\u0430\u0442\u0430\u0442\u044c \u043c\u043d\u0435 \u043d\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 &#8212; \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u043e-\u043f\u0440\u043e\u043c\u043f\u0442 \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0418\u0418, \u0447\u0442\u043e\u0431\u044b \u0412\u0415\u0421\u042c \u0442\u0435\u043a\u0441\u0442 &#8212; \u0448\u0440\u0438\u0444\u0442\u044b, \u043e\u0442\u0441\u0442\u0443\u043f\u044b, \u0446\u0432\u0435\u0442\u0430, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b &#8212; \u0438\u043c\u0435\u043b\u0438 \u041e\u0414\u0418\u041d \u0418 \u0422\u041e\u0422 \u0416\u0415 \u0441\u0442\u0438\u043b\u044c.  \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0438\u043f\u043e\u0433\u0440\u0430\u0444\u0438\u043a\u0430\u041f\u043e \u0441\u0443\u0442\u0438 &#8212; \u044d\u0442\u043e \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043f\u0430\u043f\u043a\u0435 cStyles \u043b\u0435\u0436\u0430\u0442 *Stls.ts \u0444\u0430\u0439\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:src\/styles\/\u251c\u2500\u2500 tokens.ts        \u2014 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0435 \u0442\u043e\u043a\u0435\u043d\u044b (typography, surface, radius, \u2026)\u251c\u2500\u2500 animations.ts    \u2014 transition, hover, press, enter, loading\u251c\u2500\u2500 variants.ts      \u2014 colorScheme + \u0442\u0438\u043f ColorScheme\u251c\u2500\u2500 index.ts         \u2014 \u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430, \u0440\u0435\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0451\u2514\u2500\u2500 cStyles\/         \u2014 \u0441\u0442\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0440\u0430\u0437\u0431\u0438\u0442\u044b\u0435 \u043f\u043e \u043f\u0430\u043f\u043a\u0430\u043c src\/components\/    \u251c\u2500\u2500 uiStls.ts        \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/ui\/    \u251c\u2500\u2500 commonStls.ts    \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/common\/    \u251c\u2500\u2500 layoutStls.ts    \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/layout\/    \u251c\u2500\u2500 dashboardStls.ts \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/dashboard\/    \u251c\u2500\u2500 usersStls.ts     \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/users\/    \u251c\u2500\u2500 serversStls.ts   \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 components\/servers\/    \u2514\u2500\u2500 pagesStls.ts     \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 pages\/\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0435 \u0431\u044b\u043b\u043e. \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 \u0445\u0430\u043e\u0442\u0438\u0447\u043d\u044b\u043c\u0438. \u0413\u0434\u0435 \u0442\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u043b\u0441\u044f \u0440\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u043e\u0432, \u0433\u0434\u0435-\u0442\u043e \u0446\u0432\u0435\u0442\u0430. \u0422\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043d\u0430 \u0434\u0438\u0437\u0430\u0439\u043d \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u2014 \u044d\u0442\u043e md \u0444\u0430\u0439\u043b \u043d\u0430 250+ \u0441\u0442\u0440\u043e\u043a.\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0418\u0418 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043d\u044b\u0445: Claude, Grok, Gemini, ChatGPT, Codex. \u041d\u0435 \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b \u043d\u0438 \u0446\u0435\u043d\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 15 Google-\u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u0432, \u0438 \u043b\u0438\u043c\u0438\u0442\u043e\u0432 \u043d\u0430 \u0432\u0435\u0441\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0434\u0435\u043d\u044c \u0445\u0432\u0430\u0442\u0430\u043b\u043e \u0441 \u0437\u0430\u043f\u0430\u0441\u043e\u043c.\u0428\u0442\u0443\u043a\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0418\u0418 \u0432\u0430\u0436\u0435\u043d \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u2014 \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b, \u0447\u0442\u043e \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0.env, \u043a\u0430\u043a \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f \u2014 \u0431\u043e\u043b\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0447\u0430\u043b \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0447\u0435\u0440\u0435\u0437\u00a0tar\u00a0\u0438 \u0441\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0432 \u0432 \u0447\u0430\u0442. \u0415\u0441\u043b\u0438 \u0444\u0438\u0447\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0430 \u0431\u041e\u043b\u044c\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u0436\u0438\u0433\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b \u0432\u043f\u0443\u0441\u0442\u0443\u044e.\u041d\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0440\u0443\u043a\u0430\u043c\u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u2014\u00a0.git,\u00a0venv,\u00a0node_modules,\u00a0dist\u00a0\u0438 \u043f\u0440\u043e\u0447\u0438\u0439 \u043c\u0443\u0441\u043e\u0440 \u2014 \u0442\u0430\u043a\u043e\u0435 \u0441\u0435\u0431\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043b bash-\u0441\u043a\u0440\u0438\u043f\u0442\u00a0pack.sh. \u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b:#!\/usr\/bin\/env bash## \u0421\u043a\u0440\u0438\u043f\u0442 pack \u2014 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0430 \u0447\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 htrBox \u0432 .tar \u0430\u0440\u0445\u0438\u0432\u044b# \u0412\u0441\u0435 \u0430\u0440\u0445\u0438\u0432\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\/Users\/stas\/projects\/)## \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435:#   pack          -&gt; \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u043a\u0440\u043e\u043c\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439)#   pack back     -&gt; backend + docker-compose.yaml + .env#   pack front    -&gt; frontend + docker-compose.yaml + .env#   pack &#8212;dry-run [all|back|front]  -&gt; \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 tar, \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c#set -euo pipefail# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;#          \u0416\u0401\u0421\u0422\u041a\u041e \u0417\u0410\u0425\u0410\u0420\u0414\u041a\u041e\u0416\u0415\u041d\u041d\u042b\u0415 \u041f\u0423\u0422\u0418# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;readonly PROJECT_ROOT=&#187;\/Users\/stas\/projects\/htrBox&#187;readonly OUTPUT_DIR=&#187;$(dirname &#171;$PROJECT_ROOT&#187;)&#187;   # -&gt; \/Users\/stas\/projectsreadonly PROJECT_NAME=&#187;htrBox&#187;# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;#     \u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 (\u043f\u0440\u0438 pack \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432)# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;declare -a EXCLUDES=(    &#171;.git&#187;    &#171;.env&#187;    &#171;backend\/venv&#187;    &#171;backend\/.DS_Store&#187;    &#171;frontend\/node_modules&#187;    &#171;frontend\/.DS_Store&#187;    &#171;frontend\/package-lock.json&#187;    &#171;.DS_Store&#187;    &#171;other&#187;    &#171;exclude.txt&#187;)\u0438 \u0442\u0434 &#8230;\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0442\u0440\u044e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u0420\u0430\u043d\u044c\u0448\u0435 \u044f \u0441\u0440\u0430\u0437\u0443 \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u0418\u0418: \u00ab\u0434\u0430\u0432\u0430\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0444\u0438\u0447\u0443\u00bb. \u0422\u0435\u043f\u0435\u0440\u044c \u2014 \u043d\u0435\u0442. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u043e\u0432\u043e\u0440\u044e:\u00a0\u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0439 \u043a\u043e\u0434. \u041e\u043f\u0438\u0448\u0438 \u043f\u043b\u0430\u043d \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0444\u0438\u0447\u0438 \u0441 TODO-\u043c\u0430\u0440\u043a\u0435\u0440\u0430\u043c\u0438 \u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u2014 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0432 \u0442\u0435\u043c\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u043d\u044f\u043b \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c. \u041c\u044b \u043e\u0431\u043a\u0430\u0448\u043b\u0438\u0432\u0430\u043b\u0438 \u043f\u043b\u0430\u043d, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u044f \u0434\u0430\u0432\u0430\u043b \u043a\u043e\u043c\u0430\u043d\u0434\u0443: \u0432\u043f\u0435\u0440\u0451\u0434, \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430.\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043f\u0440\u043e\u0441\u0438\u043b \u0418\u0418 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c\u00a0\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b\u00a0\u2014 \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d\u043d\u044b\u0439 TODO \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u043e\u043c \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430. \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0444\u0430\u0439\u043b\u044b, \u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0447\u0435\u0440\u0435\u0437\u00a0git dif\u00a0 \u0432 VSCode, \u0447\u0442\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u043a \u2014 \u0434\u0432\u0438\u0433\u0430\u043b\u0438\u0441\u044c \u0434\u0430\u043b\u044c\u0448\u0435.\u041a\u0441\u0442\u0430\u0442\u0438, GitKraken \u2014 \u0442\u043e\u043f. \u0420\u0430\u043d\u044c\u0448\u0435 \u0441\u0438\u0434\u0435\u043b \u043d\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u00a0tig, \u043d\u043e GitKraken \u0443\u0434\u043e\u0431\u043d\u0435\u0435, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0435\u0442\u043e\u043a. \u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u2014 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \ud83d\ude42\u0422\u0430\u043a \u0432 \u0447\u0451\u043c \u043a\u0430\u0439\u0444 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430? \u041a\u043e\u0433\u0434\u0430 \u0418\u0418 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0433\u0430\u043b\u043b\u044e\u0446\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d\u044b \u043d\u0430 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0435 \u2014 \u043d\u0435 \u0441\u0442\u0440\u0430\u0448\u043d\u043e. \u041c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c\u00a0.\/pack.sh, \u043f\u0435\u0440\u0435\u043a\u0438\u043d\u0443\u0442\u044c \u0430\u0440\u0445\u0438\u0432 \u0441 \u0430\u043a\u0442\u0443\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 TODO, \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u0433\u0434\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f.\u042f \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0445\u043e\u0434 \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u0434 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f Claude, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 tar \u0430\u0440\u0445\u0438\u0432\u0430\u043c\u0438 (\u043a\u0430\u043a \u0438 Manus). \u041d\u0430\u043f\u0438\u0441\u0430\u0432 \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u0444\u0440\u043e\u043d\u0442\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0432\u0441\u044e \u044d\u0442\u0443 \u0448\u0430\u0440\u043c\u0430\u043d\u043a\u0443, \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043a\u0443\u0447\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u0411\u044d\u043a\u0435\u043d\u0434 \u0435\u0441\u0442\u044c, \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u2014 \u043d\u043e \u043a\u0430\u043a \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u043e \u0444\u0440\u043e\u043d\u0442\u0430? \u041f\u0440\u0438\u0447\u0451\u043c \u043d\u0435 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e. \u041a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0432\u0445\u043e\u0434? \u041a\u0430\u043a \u043d\u0435 \u0434\u043e\u043b\u0431\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043b\u0438\u0448\u043d\u0438\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435? \u0412\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u044b\u043b\u043e \u043c\u043d\u043e\u0433\u043e.\u041d\u0430\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u0441 \u0418\u0418, \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439 DOM-\u0434\u0435\u0440\u0435\u0432\u0430 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u043b \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0441\u0442\u0435\u043a:TanStack Query\u00a0\u2014 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435Zustand + localStorage\u00a0\u2014 \u0434\u043b\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0441\u0441\u0438\u044f\u043c\u0438wouter\u00a0\u2014 \u043b\u0451\u0433\u043a\u0438\u0439 \u0440\u043e\u0443\u0442\u0435\u0440 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0449\u0435 React RouterhttpOnly cookie\u00a0\u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f refresh token; \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0431\u044d\u043a\u0435\u043d\u0434\u0430\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u043e\u043d\u0443\u0442\u044c \u0432 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u0434\u0435\u043b\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0438\u043d\u0438-\u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u0447\u0435\u0440\u0435\u0437 TanStack Query \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Zustand + cookie. \u041d\u0443 \u0438 \u0437\u0430\u043e\u0434\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0441\u044f, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.\u0415\u0449\u0451 \u043e\u0442\u043a\u0440\u044b\u043b \u0434\u043b\u044f \u0441\u0435\u0431\u044f\u00a0Postman. \u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c API \u2014 \u043a\u0430\u0439\u0444. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u043d\u0430\u044f \u0444\u0438\u0447\u0430 \u2014 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437: \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c pre- \u0438&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-480575","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/480575","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=480575"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/480575\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=480575"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=480575"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=480575"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}