{
  "info": {
    "_postman_id": "unison-api-v1",
    "name": "Unison API",
    "description": "REST API для фронтенда Unison (Vue SPA).\n\nБазовый URL задаётся переменной `baseUrl`:\n- local: `http://api.basisgg.local`\n- dev: `https://api.basisgg.com`\n\nКоллекция синхронизируется с endpoint'ами, которые использует фронт. Новые методы добавлять сюда при реализации.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://api.basisgg.local",
      "type": "string"
    },
    {
      "key": "authToken",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "v1",
      "description": "Публичные и авторизованные методы API v1.",
      "item": [
        {
          "name": "Public",
          "description": "Методы без авторизации — используются при загрузке приложения и на гостевых экранах.",
          "item": [
            {
              "name": "Health",
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/health/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "health", ""]
                },
                "description": "Проверка доступности API.\n\n**Фронт:** `fetchHealth()` → `src/api/health.ts`, компонент `ApiHealthCheck.vue`.\n\n**Контроллер:** `Prakter\\Controller\\HealthController::getAction()`"
              },
              "response": [
                {
                  "name": "200 OK",
                  "originalRequest": {
                    "method": "GET",
                    "header": [],
                    "url": {
"raw": "{{baseUrl}}/api/v1/health/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "health", ""]
                    }
                  },
                  "status": "OK",
                  "code": 200,
                  "_postman_previewlanguage": "json",
                  "header": [
                    {
                      "key": "Content-Type",
                      "value": "application/json"
                    }
                  ],
                  "body": "{\n  \"status\": \"ok\",\n  \"message\": \"Unison API\",\n  \"service\": \"prakter\",\n  \"timestamp\": \"2026-07-10T09:14:30+03:00\"\n}"
                }
              ]
            },
            {
              "name": "Bootstrap",
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "http://127.0.0.1:5173",
                    "description": "Опционально — для проверки CORS",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/bootstrap/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "bootstrap", ""]
                },
                "description": "Базовый контент и настройки для рендера UI без авторизации: брендинг, навигация, гостевой dashboard, тексты auth-экрана, promo.\n\n**Фронт:** `fetchBootstrap()` → `src/api/bootstrap.ts`, store `useAppStore` (загрузка в `main.ts`).\n\n**Контроллер:** `Prakter\\Controller\\BootstrapController::getAction()`\n**Сервис:** `Prakter\\Service\\UnisonBootstrapService`"
              },
              "response": [
                {
                  "name": "200 OK (guest)",
                  "originalRequest": {
                    "method": "GET",
                    "header": [],
                    "url": {
                      "raw": "{{baseUrl}}/api/v1/bootstrap",
                      "host": ["{{baseUrl}}"],
                      "path": ["api", "v1", "bootstrap"]
                    }
                  },
                  "status": "OK",
                  "code": 200,
                  "_postman_previewlanguage": "json",
                  "header": [
                    {
                      "key": "Content-Type",
                      "value": "application/json"
                    }
                  ],
                  "body": "{\n  \"status\": \"ok\",\n  \"app\": {\n    \"name\": \"Unison\",\n    \"tagline\": \"В унисон со своим телом\",\n    \"version\": \"0.1.0\"\n  },\n  \"dashboard\": {\n    \"stats\": {\n      \"files\": 0,\n      \"biomarkers\": 0,\n      \"snpPoints\": 0,\n      \"dataCompleteness\": 0,\n      \"dataTypesFilled\": 0,\n      \"dataTypesTotal\": 6,\n      \"risksHigh\": 0,\n      \"risksMed\": 0,\n      \"risksLow\": 0,\n      \"risksNoData\": 0,\n      \"risksNeedTests\": 0\n    },\n    \"accordionRows\": [],\n    \"attentionItems\": [],\n    \"collect\": {\n      \"title\": \"Собери анализы в одном месте\",\n      \"subtitle\": \"Загрузи результаты откуда угодно — распознаем показатели и покажем, что они значат.\"\n    }\n  },\n  \"navigation\": {\n    \"tabs\": [\n      { \"id\": \"home\", \"icon\": \"home\", \"label\": \"Главная\" },\n      { \"id\": \"data\", \"icon\": \"data\", \"label\": \"Данные\" },\n      { \"id\": \"risks\", \"icon\": \"risks\", \"label\": \"Риски\" },\n      { \"id\": \"rec\", \"icon\": \"rec\", \"label\": \"Рекомендации\" },\n      { \"id\": \"buy\", \"icon\": \"buy\", \"label\": \"Покупки\" }\n    ],\n    \"stubTabs\": {\n      \"data\": { \"title\": \"Данные\", \"lines\": [\"...\"] },\n      \"risks\": { \"title\": \"Риски\", \"lines\": [\"...\"] },\n      \"rec\": { \"title\": \"Рекомендации\", \"lines\": [\"...\"] },\n      \"buy\": { \"title\": \"Покупки\", \"lines\": [\"...\"] }\n    }\n  },\n  \"auth\": {\n    \"heroTitle\": \"Собери здоровье в одном месте\",\n    \"heroSubtitle\": \"Загружай анализы, узнавай риски и получай персональные рекомендации — в унисон со своим телом.\",\n    \"heroValues\": [\n      \"Анализы из любых источников в одном профиле\",\n      \"Риски, рассчитанные по твоим данным\",\n      \"Персональные нормы по генетике\"\n    ]\n  },\n  \"promo\": {\n    \"tier\": \"Бесплатный\",\n    \"title\": \"Открой персональные нормы по генетике\",\n    \"button\": \"Узнать →\"\n  }\n}"
                }
              ]
            },
            {
              "name": "Bootstrap — OPTIONS (CORS preflight)",
              "request": {
                "method": "OPTIONS",
                "header": [
                  {
                    "key": "Origin",
                    "value": "http://127.0.0.1:5173"
                  },
                  {
                    "key": "Access-Control-Request-Method",
                    "value": "GET"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/bootstrap/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "bootstrap", ""]
                },
                "description": "Preflight-запрос браузера перед cross-origin GET. Ожидается `204 No Content`."
              },
              "response": []
            }
          ]
        },
        {
          "name": "Auth",
          "description": "Bearer-токены Unison API. Не создают Bitrix cookie-сессию — сайт ЛК не затрагивается.",
          "item": [
            {
              "name": "Login",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "if (pm.response.code === 200) {",
                      "  const json = pm.response.json();",
                      "  if (json.token) pm.collectionVariables.set('authToken', json.token);",
                      "}"
                    ],
                    "type": "text/javascript"
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Content-Type", "value": "application/json" }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"phone\": \"+77000000000\",\n  \"password\": \"password123\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/login/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "login", ""]
                },
                "description": "Вход по телефону и паролю. Возвращает bearer-токен в UF пользователя.\n\n**Фронт:** `loginApi()` → `src/api/auth.ts`"
              },
              "response": []
            },
            {
              "name": "Register",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "if (pm.response.code === 200) {",
                      "  const json = pm.response.json();",
                      "  if (json.token) pm.collectionVariables.set('authToken', json.token);",
                      "}"
                    ],
                    "type": "text/javascript"
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Content-Type", "value": "application/json" }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Тест\",\n  \"phone\": \"+77001112233\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/register/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "register", ""]
                },
                "description": "Регистрация пациента. Пароль опционален — если не передан, генерируется на сервере.\n\n**Фронт:** `registerApi()` → `src/api/auth.ts`"
              },
              "response": []
            },
            {
              "name": "Me",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/me/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "me", ""]
                },
                "description": "Текущий пользователь по bearer-токену.\n\nАльтернатива при nginx без `fastcgi_param HTTP_AUTHORIZATION`: заголовок `X-Unison-Token: {{authToken}}`.\n\n**Фронт:** `meApi()` → `restoreSession()` в `src/stores/auth.ts`"
              },
              "response": []
            },
            {
              "name": "Logout",
              "request": {
                "method": "POST",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/logout/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "logout", ""]
                },
                "description": "Отзыв токена (очистка UF полей).\n\n**Фронт:** `logoutApi()`"
              },
              "response": []
            },
            {
              "name": "SMS Send code",
              "request": {
                "method": "POST",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Content-Type", "value": "application/json" }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"phone\": \"+77009998877\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/sms/send/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "sms", "send", ""]
                },
                "description": "Отправка 6-значного кода входа по SMS (пациент ЛК).\n\n**Фронт:** `sendSmsCodeApi()`"
              },
              "response": []
            },
            {
              "name": "SMS Verify code",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "if (pm.response.code === 200) {",
                      "  const json = pm.response.json();",
                      "  if (json.token) pm.collectionVariables.set('authToken', json.token);",
                      "}"
                    ],
                    "type": "text/javascript"
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Content-Type", "value": "application/json" }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"phone\": \"+77009998877\",\n  \"code\": \"123456\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/api/v1/auth/sms/verify/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "auth", "sms", "verify", ""]
                },
                "description": "Проверка SMS-кода и выдача bearer-токена.\n\n**Фронт:** `verifySmsCodeApi()`"
              },
              "response": []
            }
          ]
        },
        {
          "name": "LK",
          "description": "Данные личного кабинета (мок на бэке). Все методы требуют `Authorization: Bearer {{authToken}}` или заголовок `X-Unison-Token: {{authToken}}` (обход nginx без fastcgi_param).\n\n**Фронт:** `src/api/lk.ts`, store `useLkStore`. Загрузка при входе (dashboard, navigation, promo, labels) и лениво при переключении вкладок (risks, data, recommendations, purchases).",
          "item": [
            {
              "name": "Dashboard",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" },
                  { "key": "X-Unison-Token", "value": "{{authToken}}", "disabled": true }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/dashboard/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "dashboard", ""]
                },
                "description": "Главная вкладка ЛК: stats, accordionRows, attentionItems, collect, uploadActions.\n\n**Фронт:** `fetchLkDashboard()`\n**Сервис:** `UnisonLkMockService::getDashboard()`"
              },
              "response": []
            },
            {
              "name": "Navigation",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/navigation/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "navigation", ""]
                },
                "description": "Вкладки и заглушки разделов: tabs, stubTabs.\n\n**Фронт:** `fetchLkNavigation()`\n**Сервис:** `UnisonLkMockService::getNavigation()`"
              },
              "response": []
            },
            {
              "name": "Promo",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/promo/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "promo", ""]
                },
                "description": "Промо-блок в сайдбаре.\n\n**Фронт:** `fetchLkPromo()`\n**Сервис:** `UnisonLkMockService::getPromo()`"
              },
              "response": []
            },
            {
              "name": "Labels",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/labels/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "labels", ""]
                },
                "description": "Подписи UI ЛК (приветствие с именем, кнопки, заголовки секций).\n\n**Фронт:** `fetchLkLabels()`\n**Сервис:** `UnisonLkMockService::getLabels()`"
              },
              "response": []
            },
            {
              "name": "Risks",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/risks/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "risks", ""]
                },
                "description": "Вкладка «Риски»: сводка, фильтры, карточки рисков с анализами и генетикой (мок из `markup/proto-health-risks.html`).\n\n**Фронт:** `fetchLkRisks()` → `LkRisksTab.vue`\n**Сервис:** `UnisonLkTabsMockService::getRisks()`"
              },
              "response": []
            },
            {
              "name": "Data",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/data/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "data", ""]
                },
                "description": "Вкладка «Данные»: загрузка анализов, показатели, документы, фенотип, гентест (мок из `markup/proto-health-analyses.html`).\n\n**Фронт:** `fetchLkData()` → `LkDataTab.vue`\n**Сервис:** `UnisonLkTabsMockService::getData()`"
              },
              "response": []
            },
            {
              "name": "Recommendations",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/recommendations/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "recommendations", ""]
                },
                "description": "Вкладка «Рекомендации»: образ жизни, мониторинг, питание.\n\n**Фронт:** `fetchLkRecommendations()` → `LkRecTab.vue`\n**Сервис:** `UnisonLkTabsMockService::getRecommendations()`"
              },
              "response": []
            },
            {
              "name": "Purchases",
              "request": {
                "method": "GET",
                "header": [
                  { "key": "Accept", "value": "application/json" },
                  { "key": "Authorization", "value": "Bearer {{authToken}}" }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/lk/purchases/",
                  "host": ["{{baseUrl}}"],
                  "path": ["api", "v1", "lk", "purchases", ""]
                },
                "description": "Вкладка «Покупки»: текущие заказы, каталог, история.\n\n**Фронт:** `fetchLkPurchases()` → `LkBuyTab.vue`\n**Сервис:** `UnisonLkTabsMockService::getPurchases()`"
              },
              "response": []
            }
          ]
        }
      ]
    }
  ]
}
