[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"technologies":3,"\u002Fopen-source\u002Forosu-server":167,"glossary":805},[4,10,15,21,26,32,38,43,48,53,58,63,68,73,77,82,87,92,97,103,108,113,118,123,128,133,138,143,147,152,157,162],{"title":5,"description":6,"slug":7,"category":8,"icon":9},"Android","Каждое наше приложение выходит и на Android — платформенные API, фоновое выполнение, разрешения и требования магазина вместе с ними.","android","framework","logos:android-icon",{"title":11,"description":12,"slug":13,"category":8,"icon":14},"Angular","Фронтенд-фреймворк, в котором мы работаем, когда продукт уже на Angular, — строгая структура, подходящая большим долгоживущим приложениям.","angular","logos:angular-icon",{"title":16,"description":17,"slug":18,"category":19,"icon":20},"Dart","Язык, на котором написано каждое наше Flutter-приложение, — строгая null safety, полноценный pattern matching и компиляция в нативный код и веб.","dart","language","logos:dart",{"title":22,"description":23,"slug":24,"category":8,"icon":25},"Django","Python-фреймворк, который мы берём, когда продукту нужны админка, аутентификация и модель данных в первый же день, а не самописный сервис.","django","logos:django-icon",{"title":27,"description":28,"slug":29,"category":30,"icon":31},"Docker","Каждый наш сервис поставляется в виде контейнера, поэтому на ноутбуке, в CI и в продакшене работает один и тот же артефакт, а не три разных.","docker","infrastructure","logos:docker-icon",{"title":33,"description":34,"slug":35,"category":36,"icon":37},"Fastlane","Автоматизация релизов в нашей мобильной разработке — подпись, сборки и загрузка в сторы идут из CI, а не с ноутбука одного инженера в день релиза.","fastlane","tools","logos:fastlane",{"title":39,"description":40,"slug":41,"category":8,"icon":42},"Flutter","Наш основной мобильный стек с 2018 года — одна кодовая база на Dart для iOS, Android, веба и десктопа без отдельной команды под каждую платформу.","flutter","logos:flutter",{"title":44,"description":45,"slug":46,"category":36,"icon":47},"Git","Все проекты, к которым мы прикасаемся, живут в Git — ревью пул-реквестов, CI на каждой ветке и история, понятная и спустя месяцы.","git","logos:git-icon",{"title":49,"description":50,"slug":51,"category":19,"icon":52},"Go","Наш бэкенд-язык для real-time API и сервисов под нагрузкой — маленькие бинарники, быстрая сборка и конкурентность, которая остаётся читаемой.","go","logos:gopher",{"title":54,"description":55,"slug":56,"category":30,"icon":57},"Google Cloud","Облако, в котором работают наши продакшен-нагрузки, — управляемый Kubernetes, хранилище и сеть без серверов, которые надо обслуживать руками.","gcp","logos:google-cloud",{"title":59,"description":60,"slug":61,"category":36,"icon":62},"Gradle","Система сборки, через которую проходит каждый Android-релиз, — флейворы, конфигурации подписи и вся обвязка зависимостей под Flutter-приложением.","gradle","logos:gradle",{"title":64,"description":65,"slug":66,"category":30,"icon":67},"Helm","Так мы упаковываем деплой в Kubernetes — сервис, конфигурация, секреты и ingress как одна версионируемая единица, которую можно выкатить и откатить.","helm","logos:helm",{"title":69,"description":70,"slug":71,"category":19,"icon":72},"Kotlin","То, что мы берём, когда Flutter-приложению нужен настоящий Android под ним, — platform channels, фоновые задачи и интеграции с нативными SDK.","kotlin","logos:kotlin-icon",{"title":74,"description":75,"slug":76,"category":8,"icon":72},"Kotlin Multiplatform","Общая бизнес-логика для iOS и Android, а нативный интерфейс у каждой платформы свой, — альтернатива, когда Flutter не подходит.","kmp",{"title":78,"description":79,"slug":80,"category":30,"icon":81},"Kubernetes","Так мы запускаем сервисы в продакшене — деплой в Helm-чартах, откатываемые выкатки и масштабирование, для которого не нужен человек в три ночи.","kubernetes","logos:kubernetes",{"title":83,"description":84,"slug":85,"category":30,"icon":86},"NATS","Лёгкий обмен сообщениями между сервисами — publish\u002Fsubscribe и request\u002Freply без эксплуатационного веса полноценного кластера брокера.","nats","logos:nats-icon",{"title":88,"description":89,"slug":90,"category":8,"icon":91},"Nuxt","Vue с серверным рендерингом, роутингом и SEO из коробки — так мы делаем сайты и веб-приложения, которые должны быстро грузиться и индексироваться.","nuxt","logos:nuxt-icon",{"title":93,"description":94,"slug":95,"category":19,"icon":96},"PHP","Там, где PHP-бэкенд уже есть: дорабатываем его, интегрируемся с ним и делаем мобильные и веб-клиенты, которые он обслуживает.","php","logos:php",{"title":98,"description":99,"slug":100,"category":101,"icon":102},"PostgreSQL","Наша база данных по умолчанию — от проектирования схемы до настройки индексов мы берём её, если у продукта нет конкретной причины взять другую.","postgres","database","logos:postgresql",{"title":104,"description":105,"slug":106,"category":19,"icon":107},"Python","Наш язык для бэкендов, работы с данными и AI-интеграций — включая Python-биндинги, которые мы выпускаем к собственным инструментам на Rust.","python","logos:python",{"title":109,"description":110,"slug":111,"category":8,"icon":112},"React","Фронтенд-библиотека, в которой мы работаем, когда продукт уже на React, — компоненты, хуки и выросшая вокруг них экосистема.","react","logos:react",{"title":114,"description":115,"slug":116,"category":101,"icon":117},"Redis","Место для данных, которые должны быть быстрыми и которые не жалко пересчитать, — кэши, сессии, лимиты и очереди фоновых задач.","redis","logos:redis",{"title":119,"description":120,"slug":121,"category":19,"icon":122},"Ruby","Язык, на котором написана автоматизация наших мобильных релизов, — лейны Fastlane, кастомные действия и связка с CI, доставляющая сборки в сторы.","ruby","logos:ruby",{"title":124,"description":125,"slug":126,"category":19,"icon":127},"Rust","Куда мы идём, когда важны и скорость, и корректность, — рендеринг документов, CLI-инструменты и сервисы, которые обязаны оставаться быстрыми и предсказуемыми.","rust","simple-icons:rust",{"title":129,"description":130,"slug":131,"category":101,"icon":132},"SQLite","База данных, которая поставляется внутри приложения, — локальные кэши, offline-first хранилище и всё, что должно работать без сети.","sqlite","logos:sqlite",{"title":134,"description":135,"slug":136,"category":8,"icon":137},"Strapi","Headless CMS, к которой мы обращаемся, когда контент должны вести сами редакторы, — готовая админка и чистый API вместо самописных.","strapi","logos:strapi-icon",{"title":139,"description":140,"slug":141,"category":19,"icon":142},"Swift","То, что мы берём, когда Flutter-приложению нужен настоящий iOS под ним, — platform channels, интеграции нативных SDK, виджеты и App Clips.","swift","logos:swift",{"title":144,"description":145,"slug":146,"category":8,"icon":142},"SwiftUI","UI-фреймворк Apple, на котором мы делаем нативные поверхности, недоступные Flutter-приложению, — виджеты, App Clips и расширения.","swiftui",{"title":148,"description":149,"slug":150,"category":8,"icon":151},"Tailwind CSS","Так мы стилизуем весь фронтенд — утилитарные классы и дизайн-токены вместо таблицы стилей, которая только растёт и никогда не чистится.","tailwind","logos:tailwindcss-icon",{"title":153,"description":154,"slug":155,"category":19,"icon":156},"TypeScript","Стандарт для всего, что мы пишем для браузера и для Node-сервисов, — типы ловят ошибки интеграции раньше, чем код доходит до ревью.","typescript","logos:typescript-icon",{"title":158,"description":159,"slug":160,"category":8,"icon":161},"Vue","Наш фронтенд-фреймворк для админок, дашбордов мерчантов и веб-приложений, которые должны оставаться поддерживаемыми годами, а не спринтами.","vue","logos:vue",{"title":163,"description":164,"slug":165,"category":36,"icon":166},"Whisper","Открытая модель распознавания речи от OpenAI — движок транскрипции для голосового ввода, который работает и как бэкенд-сервис, и прямо на устройстве в приложении.","whisper","simple-icons:openai",{"id":168,"title":169,"body":170,"description":776,"extension":777,"links":778,"meta":779,"metaDescription":780,"metaTitle":778,"navigation":781,"ogDescription":782,"path":783,"repository":784,"seo":788,"slug":247,"stem":789,"technologies":790,"updated":791,"__hash__":792,"stats":793},"open_source_ru\u002Fopen-source\u002Forosu-server.md","Orosu Server",{"type":171,"value":172,"toc":767},"minimark",[173,185,190,193,228,237,241,249,291,294,298,307,404,413,417,430,457,460,470,503,511,517,549,594,600,640,644,658,683,693,697,700,739,752,756,759,763],[174,175,176],"blockquote",{},[177,178,179,180,184],"p",{},"От японского 降ろす (",[181,182,183],"em",{},"órosu",") — «разгружать», «сгружать».",[186,187,189],"h2",{"id":188},"проблема","Проблема",[177,191,192],{},"CI-системы хорошо справляются со сборкой ПО и плохо — с его доставкой. Перенос артефакта сборки из пайплайна на продакшн-машину обычно сводится к одному из нескольких привычных, но хрупких паттернов:",[194,195,196,204,210,216,222],"ul",{},[197,198,199,203],"li",{},[200,201,202],"strong",{},"Приватные SSH-ключи",", скопированные в секреты CI и расползающиеся по всем пайплайнам и репозиториям, где нужен деплой",[197,205,206,209],{},[200,207,208],{},"SFTP\u002Frsync-скрипты",", скопированные из одного проекта в другой, каждый со своими, чуть отличающимися багами",[197,211,212,215],{},[200,213,214],{},"Захардкоженные пути и права доступа",", которые ломаются при малейшем изменении структуры сервера",[197,217,218,221],{},[200,219,220],{},"Продакшн-машины, напрямую доступные"," для CI-раннеров, расширяющие поверхность атаки с каждым новым пайплайном",[197,223,224,227],{},[200,225,226],{},"Разрастание секретов",", из-за которого ротация одного скомпрометированного ключа превращается в аудит всех репозиториев, которые могли на него ссылаться",[177,229,230,231,236],{},"Это не специфично для какой-то одной ",[232,233,235],"term",{"slug":234},"ci-cd","CI\u002FCD","-платформы — это стандартная форма задачи «выполнить скрипт на удалённой машине из пайплайна», и риски накапливаются с каждым проектом, который её перенимает.",[186,238,240],{"id":239},"как-orosu-решает-эту-задачу","Как Orosu решает эту задачу",[177,242,243,244,248],{},"Orosu устанавливается один раз на целевой машине как ",[245,246,247],"code",{},"orosu-server"," и превращает деплой из открытой SSH-сессии в ограниченный, аутентифицированный запрос:",[250,251,252,258,269,277,285],"ol",{},[197,253,254,257],{},[200,255,256],{},"CI собирает"," приложение — бинарник, образ контейнера, статические файлы — что бы ни производил пайплайн",[197,259,260,263,264,268],{},[200,261,262],{},"CI запускает задачу"," через соединение ",[232,265,267],{"slug":266},"websocket","WebSocket",", при необходимости прикладывая файлы",[197,270,271,276],{},[200,272,273,275],{},[245,274,247],{}," аутентифицирует"," запрос с помощью подписей Ed25519 — ни паролей, ни общих секретов при передаче",[197,278,279,284],{},[200,280,281,283],{},[245,282,247],{}," выполняет заранее заданный скрипт"," — один из фиксированного набора, настроенного на сервере, а не произвольную команду от CI",[197,286,287,290],{},[200,288,289],{},"Скрипт выполняет деплой",", используя файлы и аргументы, приложенные к задаче",[177,292,293],{},"Никакого прямого SSH, никакого жонглирования учётными данными в каждом пайплайне и никакой серверной поверхности за пределами конкретных скриптов, явно настроенных оператором.",[186,295,297],{"id":296},"установка","Установка",[177,299,300,302,303,306],{},[245,301,247],{}," и сопутствующий CLI ",[245,304,305],{},"orosu-keygen"," поставляются как пакеты для Debian\u002FUbuntu из apt-репозитория:",[308,309,314],"pre",{"className":310,"code":311,"language":312,"meta":313,"style":313},"language-shell shiki shiki-themes material-theme-lighter github-light github-dark","curl -fsSL https:\u002F\u002Fpackages.nerdy.pro\u002FNerdyPro.gpg | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fnerdy-pro.gpg\necho \"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fnerdy-pro.gpg] https:\u002F\u002Fpackages.nerdy.pro\u002F stable main\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fnerdy-pro.list\nsudo apt update\nsudo apt install orosu\n","shell","",[245,315,316,352,379,391],{"__ignoreMap":313},[317,318,321,325,329,333,337,340,343,346,349],"span",{"class":319,"line":320},"line",1,[317,322,324],{"class":323},"sbgvK","curl",[317,326,328],{"class":327},"stzsN"," -fsSL",[317,330,332],{"class":331},"s_sjI"," https:\u002F\u002Fpackages.nerdy.pro\u002FNerdyPro.gpg",[317,334,336],{"class":335},"smGrS"," |",[317,338,339],{"class":323}," sudo",[317,341,342],{"class":331}," gpg",[317,344,345],{"class":327}," --dearmor",[317,347,348],{"class":327}," -o",[317,350,351],{"class":331}," \u002Fusr\u002Fshare\u002Fkeyrings\u002Fnerdy-pro.gpg\n",[317,353,355,359,363,366,369,371,373,376],{"class":319,"line":354},2,[317,356,358],{"class":357},"sptTA","echo",[317,360,362],{"class":361},"sjJ54"," \"",[317,364,365],{"class":331},"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fnerdy-pro.gpg] https:\u002F\u002Fpackages.nerdy.pro\u002F stable main",[317,367,368],{"class":361},"\"",[317,370,336],{"class":335},[317,372,339],{"class":323},[317,374,375],{"class":331}," tee",[317,377,378],{"class":331}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fnerdy-pro.list\n",[317,380,382,385,388],{"class":319,"line":381},3,[317,383,384],{"class":323},"sudo",[317,386,387],{"class":331}," apt",[317,389,390],{"class":331}," update\n",[317,392,394,396,398,401],{"class":319,"line":393},4,[317,395,384],{"class":323},[317,397,387],{"class":331},[317,399,400],{"class":331}," install",[317,402,403],{"class":331}," orosu\n",[177,405,406,407,409,410,412],{},"GitHub Releases также публикует готовые бинарники ",[245,408,247],{}," и ",[245,411,305],{}," напрямую — для машин, на которые нельзя добавить apt-репозиторий.",[186,414,416],{"id":415},"быстрый-старт","Быстрый старт",[177,418,419,422,423,425,426,429],{},[200,420,421],{},"Сгенерируйте пару ключей клиента"," с помощью ",[245,424,305],{},", находясь в ",[245,427,428],{},"\u002Fetc\u002Forosu",":",[308,431,433],{"className":310,"code":432,"language":312,"meta":313,"style":313},"orosu-keygen --name my-ci-client --private-key-output my-ci-client.key --public-key-output my-ci-client.pub\n",[245,434,435],{"__ignoreMap":313},[317,436,437,439,442,445,448,451,454],{"class":319,"line":320},[317,438,305],{"class":323},[317,440,441],{"class":327}," --name",[317,443,444],{"class":331}," my-ci-client",[317,446,447],{"class":327}," --private-key-output",[317,449,450],{"class":331}," my-ci-client.key",[317,452,453],{"class":327}," --public-key-output",[317,455,456],{"class":331}," my-ci-client.pub\n",[177,458,459],{},"Публичный ключ идёт в конфиг сервера; приватный становится секретом CI.",[177,461,462,465,466,469],{},[200,463,464],{},"Настройте сервер"," в ",[245,467,468],{},"\u002Fetc\u002Forosu\u002Forosu-server.toml"," — адрес прослушивания и публичный ключ клиента:",[308,471,475],{"className":472,"code":473,"language":474,"meta":313,"style":313},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","listen:\n  tcp: \"127.0.0.1:8081\"\nclients:\n  - name: my-ci-client\n    secret_file: \u002Fetc\u002Forosu\u002Fmy-ci-client.pub\n","yaml",[245,476,477,482,487,492,497],{"__ignoreMap":313},[317,478,479],{"class":319,"line":320},[317,480,481],{},"listen:\n",[317,483,484],{"class":319,"line":354},[317,485,486],{},"  tcp: \"127.0.0.1:8081\"\n",[317,488,489],{"class":319,"line":381},[317,490,491],{},"clients:\n",[317,493,494],{"class":319,"line":393},[317,495,496],{},"  - name: my-ci-client\n",[317,498,500],{"class":319,"line":499},5,[317,501,502],{},"    secret_file: \u002Fetc\u002Forosu\u002Fmy-ci-client.pub\n",[177,504,505,506,510],{},"Сервер, слушающий localhost, обычно стоит за обратным прокси, который терминирует ",[232,507,509],{"slug":508},"tls","TLS"," и пробрасывает апгрейды WebSocket — в README приведена конфигурация nginx для этого случая.",[177,512,513,516],{},[200,514,515],{},"Определите скрипт",", который клиенту разрешено запускать:",[308,518,522],{"className":519,"code":520,"language":521,"meta":313,"style":313},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","#!\u002Fbin\u002Fbash\necho \"Hello, $1!\"\n","bash",[245,523,524,530],{"__ignoreMap":313},[317,525,526],{"class":319,"line":320},[317,527,529],{"class":528},"sutJx","#!\u002Fbin\u002Fbash\n",[317,531,532,534,536,539,543,546],{"class":319,"line":354},[317,533,358],{"class":357},[317,535,362],{"class":361},[317,537,538],{"class":331},"Hello, ",[317,540,542],{"class":541},"sfi6f","$1",[317,544,545],{"class":331},"!",[317,547,548],{"class":361},"\"\n",[308,550,552],{"className":472,"code":551,"language":474,"meta":313,"style":313},"clients:\n  - name: my-ci-client\n    secret_file: \u002Fetc\u002Forosu\u002Fmy-ci-client.pub\n    scripts:\n      - name: test-script\n        command:\n          - \"bash\"\n          - \"\u002Fetc\u002Forosu\u002Fscripts\u002Ftest.sh\"\n",[245,553,554,558,562,566,571,576,582,588],{"__ignoreMap":313},[317,555,556],{"class":319,"line":320},[317,557,491],{},[317,559,560],{"class":319,"line":354},[317,561,496],{},[317,563,564],{"class":319,"line":381},[317,565,502],{},[317,567,568],{"class":319,"line":393},[317,569,570],{},"    scripts:\n",[317,572,573],{"class":319,"line":499},[317,574,575],{},"      - name: test-script\n",[317,577,579],{"class":319,"line":578},6,[317,580,581],{},"        command:\n",[317,583,585],{"class":319,"line":584},7,[317,586,587],{},"          - \"bash\"\n",[317,589,591],{"class":319,"line":590},8,[317,592,593],{},"          - \"\u002Fetc\u002Forosu\u002Fscripts\u002Ftest.sh\"\n",[177,595,596,599],{},[200,597,598],{},"Запустите его из CI"," с помощью сопутствующего GitHub Action, передав адрес сервера и приватный ключ клиента через секреты:",[308,601,603],{"className":472,"code":602,"language":474,"meta":313,"style":313},"- name: Remotely execute a script\n  uses: orosu-ci\u002Forosu@v0\n  with:\n    address: ${{ secrets.OROSU_SERVER_URL }}\n    script: test-script\n    key: ${{ secrets.OROSU_CLIENT_KEY }}\n    arguments: \"from CI pipeline\"\n",[245,604,605,610,615,620,625,630,635],{"__ignoreMap":313},[317,606,607],{"class":319,"line":320},[317,608,609],{},"- name: Remotely execute a script\n",[317,611,612],{"class":319,"line":354},[317,613,614],{},"  uses: orosu-ci\u002Forosu@v0\n",[317,616,617],{"class":319,"line":381},[317,618,619],{},"  with:\n",[317,621,622],{"class":319,"line":393},[317,623,624],{},"    address: ${{ secrets.OROSU_SERVER_URL }}\n",[317,626,627],{"class":319,"line":499},[317,628,629],{},"    script: test-script\n",[317,631,632],{"class":319,"line":578},[317,633,634],{},"    key: ${{ secrets.OROSU_CLIENT_KEY }}\n",[317,636,637],{"class":319,"line":584},[317,638,639],{},"    arguments: \"from CI pipeline\"\n",[186,641,643],{"id":642},"сквозное-шифрование","Сквозное шифрование",[177,645,646,647,649,650,652,653,657],{},"WSS\u002F:term",[317,648,509],{"slug":508}," защищает соединение, но когда TLS терминируется на обратном прокси перед ",[245,651,247],{}," — как в стандартной схеме выше — аргументы скрипта, загруженные файлы и потоковый вывод остаются на этом прокси открытым текстом. Опциональное рукопожатие ",[232,654,656],{"slug":655},"end-to-end-encryption","сквозного шифрования"," (X25519 + HKDF-SHA256 + ChaCha20-Poly1305) закрывает эту брешь:",[308,659,661],{"className":310,"code":660,"language":312,"meta":313,"style":313},"orosu-keygen --kind server --private-key-output server.key --public-key-output server.pub\n",[245,662,663],{"__ignoreMap":313},[317,664,665,667,670,673,675,678,680],{"class":319,"line":320},[317,666,305],{"class":323},[317,668,669],{"class":327}," --kind",[317,671,672],{"class":331}," server",[317,674,447],{"class":327},[317,676,677],{"class":331}," server.key",[317,679,453],{"class":327},[317,681,682],{"class":331}," server.pub\n",[177,684,685,686,689,690,692],{},"Публичный ключ сервера добавляется в его конфиг и передаётся в CI как входной параметр ",[245,687,688],{},"server_key"," экшена. Переход на него добровольный, и каждая сторона включает его независимо от другой: сервер с настроенным шифрованием по-прежнему обслуживает клиентов, которые не передают ",[245,691,688],{},", точно так же, как раньше, и скоординированного обновления не требуется.",[186,694,696],{"id":695},"безопасность","Безопасность",[177,698,699],{},"Безопасность заложена в проект с самого начала, а не добавлена постфактум:",[194,701,702,708,714,720,726],{},[197,703,704,707],{},[200,705,706],{},"Криптографическая аутентификация"," — каждая задача подписывается ключом Ed25519 клиента; в канале нет ни пароля, ни общего секрета, который мог бы перехватить атакующий.",[197,709,710,713],{},[200,711,712],{},"Закрытый набор действий"," — CI может запускать только те скрипты, которые оператор явно задал на сервере. Пути от задачи CI к произвольной команде оболочки не существует.",[197,715,716,719],{},[200,717,718],{},"Защищённая обработка вложений"," — имена записей в zip проверяются на обход путей, а количество записей и суммарный размер после распаковки ограничены, поэтому специально сформированное или чрезмерно большое вложение не может выйти за пределы каталога извлечения или исчерпать место на диске.",[197,721,722,725],{},[200,723,724],{},"Эшелонированная защита"," — опциональное рукопожатие сквозного шифрования проверяет обмен X25519 на атаки low-order-point, дополняя конфиденциальность, которую оно и так обеспечивает.",[197,727,728,731,732,734,735,738],{},[200,729,730],{},"Безопасные права доступа по умолчанию"," — ",[245,733,305],{}," записывает файлы приватных ключей с правами ",[245,736,737],{},"0600"," независимо от текущего umask.",[177,740,741,742,751],{},"Эти механизмы вошли в релиз 0.7.0 как обновление, не требующее дополнительных действий — без изменений конфига, CLI или протокола. Полную историю релизов см. в ",[743,744,748],"a",{"href":745,"rel":746},"https:\u002F\u002Fgithub.com\u002Forosu-ci\u002Fserver\u002Fblob\u002Fmain\u002FCHANGELOG.md",[747],"nofollow",[245,749,750],{},"CHANGELOG.md",".",[186,753,755],{"id":754},"лицензия","Лицензия",[177,757,758],{},"Orosu распространяется под лицензией Apache-2.0.",[760,761],"questions",{":items":762},"[{\"title\":\"Что заменяет orosu-server?\",\"text\":\"Разрозненные шаги деплоя по SSH\u002FSCP в CI-пайплайнах — приватные ключи в секретах, скопированные rsync-скрипты и напрямую доступные продакшн-серверы. CI запускает аутентифицированную задачу по WebSocket вместо открытия SSH-сессии.\"},{\"title\":\"Как работает аутентификация?\",\"text\":\"У каждого CI-клиента есть пара ключей Ed25519. Публичный ключ регистрируется в конфиге сервера; приватный хранится как секрет CI и используется для подписи запросов на выполнение задач. Сервер выполняет только те скрипты, которые явно настроены для этого клиента.\"},{\"title\":\"Может ли CI выполнять произвольные команды на сервере?\",\"text\":\"Нет. orosu-server выполняет только заранее заданные скрипты, настроенные в orosu-server.toml. Задача CI выбирает скрипт по имени и передаёт аргументы и вложения — она не может передать произвольную команду.\"},{\"title\":\"Шифруется ли соединение?\",\"text\":\"По умолчанию соединение защищено WSS\u002FTLS, обычно терминируемым на обратном прокси перед orosu-server. Можно включить опциональный слой сквозного шифрования (X25519 + ChaCha20-Poly1305), чтобы аргументы скрипта, файлы и вывод оставались конфиденциальными даже для этого прокси.\"},{\"title\":\"Как устанавливается orosu-server?\",\"text\":\"Через apt-репозиторий (packages.nerdy.pro) для Debian\u002FUbuntu, либо в виде готовых бинарников, прикреплённых к GitHub Releases, для orosu-server и CLI orosu-keygen.\"},{\"title\":\"Какие меры безопасности реализованы в orosu-server?\",\"text\":\"Подписанные Ed25519 запросы, закрытый набор скриптов, заданных на сервере и доступных для запуска из CI, защита от обхода путей и ограничения размера при извлечении вложений, защита от атаки low-order-point в опциональном рукопожатии сквозного шифрования и безопасные права доступа по умолчанию для сгенерированных ключей.\"}]",[764,765,766],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sfi6f, html code.shiki .sfi6f{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit}",{"title":313,"searchDepth":354,"depth":354,"links":768},[769,770,771,772,773,774,775],{"id":188,"depth":354,"text":189},{"id":239,"depth":354,"text":240},{"id":296,"depth":354,"text":297},{"id":415,"depth":354,"text":416},{"id":642,"depth":354,"text":643},{"id":695,"depth":354,"text":696},{"id":754,"depth":354,"text":755},"Безопасный инструмент доставки для CI\u002FCD, который заменяет разрозненные SSH\u002FSCP-шаги в GitHub Actions и других CI-пайплайнах аутентифицированными задачами по WebSocket, выполняющими заранее заданные скрипты на целевой машине.","md",null,{},"Orosu заменяет SSH\u002FSCP-деплой в CI аутентифицированными WebSocket-задачами, которые запускают заданные скрипты на вашем сервере.",true,"Учётные данные CI не должны давать доступ к командной оболочке. Orosu даёт им ровно один именованный скрипт — через аутентифицированную WebSocket-задачу.","\u002Fopen-source\u002Forosu-server",{"type":785,"company":786,"name":787},"github","orosu-ci","server",{"title":169,"description":776},"open-source\u002Forosu-server",[126],"2026-08-06","GFM2En67-Ob2q5qPChbwBGEp6lFT5vz5VUXpotGcwhw",{"forks":794,"stars":320,"contributors":795,"last_release":801,"issues":794,"has_contribution_guide":802,"license":803,"last_updated":804,"watchers":320},0,[796],{"login":797,"profile_url":798,"avatar_url":799,"contributions":800},"thenixan","https:\u002F\u002Fgithub.com\u002Fthenixan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F3602098?v=4",271,"v0.7.0",false,"Apache-2.0","2026-08-07T12:57:55Z",[806,820,833,848,860,875,891,904,916,933,946,957,967,980,992,1003,1012,1026,1039,1046,1060,1075,1088,1101,1114,1125,1136,1147,1160,1170,1183,1195,1206,1217,1231,1239,1250,1263,1276,1289,1302,1314,1326,1338,1350,1362,1373,1387,1398,1409,1420,1433,1445],{"slug":807,"term":808,"definition":809,"category":810,"aliases":811,"links":813,"related":817,"readMore":-1,"target":819,"hasArticle":802},"aosp","AOSP","Android Open Source Project — Android без надстройки Google, который может форкнуть кто угодно. На его форках работают кассовые терминалы, киоски и автомобильные системы, а работа на этом уровне открывает части ОС, которых прикладной разработчик не видит.","platform",[812],"Android Open Source Project",[814],{"kind":815,"url":816},"website","https:\u002F\u002Fsource.android.com\u002F",[818],"host-card-emulation","\u002Fglossary#aosp",{"slug":821,"term":822,"definition":823,"category":810,"aliases":824,"links":825,"related":829,"readMore":-1,"target":832,"hasArticle":802},"app-clips","App Clips","Функция Apple, позволяющая запустить небольшую часть iOS-приложения — до 15 МБ — не устанавливая его целиком. Вызывается по QR-коду, NFC-метке или ссылке: для случаев, когда первое действие пользователя не должно требовать похода в App Store.",[],[826],{"kind":827,"url":828},"documentation","https:\u002F\u002Fdeveloper.apple.com\u002Fapp-clips\u002F",[830,831],"deep-linking","install-referrer","\u002Fglossary#app-clips",{"slug":834,"term":835,"definition":836,"category":810,"aliases":837,"links":838,"related":844,"readMore":-1,"target":847,"hasArticle":802},"bigquery","BigQuery","Аналитическое хранилище Google Cloud. Вы запускаете SQL по миллиардам строк, и они сканируются за секунды, а данные при этом лежат отдельно от машин, выполняющих запросы. Именно это снимает отчётность и исследование данных с базы, обслуживающей живой трафик.",[],[839,841],{"kind":815,"url":840},"https:\u002F\u002Fcloud.google.com\u002Fbigquery",{"kind":842,"url":843},"wikipedia","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBigQuery",[845,846],"object-storage","elasticsearch","\u002Fglossary#bigquery",{"slug":234,"term":235,"definition":849,"category":850,"aliases":851,"links":855,"related":858,"readMore":-1,"target":859,"hasArticle":802},"Автоматизация, которая собирает, тестирует и выкладывает каждое изменение без ручного запуска команд. В мобильной разработке это то, что превращает релиз в нажатие кнопки вместо полудня ожидания, пока освободится нужный человек.","practice",[852,853,854],"CI","непрерывная интеграция","непрерывная поставка",[856],{"kind":842,"url":857},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCI\u002FCD",[],"\u002Fglossary#ci-cd",{"slug":861,"term":862,"definition":863,"category":864,"aliases":865,"links":868,"related":871,"readMore":-1,"target":874,"hasArticle":802},"crud","CRUD","Create, read, update, delete — четыре операции, стоящие почти за каждой формой и админкой. Собирательное название для рутинной половины приложения, которая управляет данными, в отличие от частей с реальной предметной логикой.","architecture",[866,867],"Create, Read, Update, Delete","создание, чтение, обновление, удаление",[869],{"kind":842,"url":870},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCreate,_read,_update_and_delete",[872,873],"rest","graphql","\u002Fglossary#crud",{"slug":876,"term":877,"definition":878,"category":850,"aliases":879,"links":883,"related":888,"readMore":-1,"target":890,"hasArticle":802},"dev-container","Dev Container","Среда разработки, описанная один раз в devcontainer.json — ОС, инструменты и версии рантаймов, которые нужны проекту, — и открываемая одинаково внутри контейнера в редакторе любого участника, вместо инструкции по установке, которую каждый понимает по-своему.",[880,881,882],"devcontainer.json","Dev Containers","VS Code Dev Containers",[884,886],{"kind":815,"url":885},"https:\u002F\u002Fcontainers.dev\u002F",{"kind":827,"url":887},"https:\u002F\u002Fcode.visualstudio.com\u002Fdocs\u002Fdevcontainers\u002Fcontainers",[889],"container-registry","\u002Fglossary#dev-container",{"slug":846,"term":892,"definition":893,"category":810,"aliases":894,"links":897,"related":902,"readMore":-1,"target":903,"hasArticle":802},"Elasticsearch","Поисковый и аналитический движок, который индексирует записи, чтобы их можно было интерактивно фильтровать и искать, а не сканировать. К нему обращаются, когда вопрос звучит как «покажи вот эти сессии с шестью фильтрами», а не «просуммируй колонку».",[895,896],"Elastic","ELK",[898,900],{"kind":815,"url":899},"https:\u002F\u002Fwww.elastic.co\u002Felasticsearch",{"kind":842,"url":901},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FElasticsearch",[834],"\u002Fglossary#elasticsearch",{"slug":905,"term":906,"definition":907,"category":864,"aliases":908,"links":911,"related":912,"readMore":-1,"target":915,"hasArticle":802},"fan-out","Fan-out","Чтение источника один раз и доставка каждого обновления всем подписанным на него клиентам. Наивная версия пишет подписчикам в цикле и встаёт, как только один из сокетов начинает тормозить; рабочая — держит отдельный буфер на каждого клиента и отключает тех, кто не успевает.",[909,910],"веерная рассылка","фан-аут",[],[266,913,914],"pub-sub","server-sent-events","\u002Fglossary#fan-out",{"slug":917,"term":918,"definition":919,"category":850,"aliases":920,"links":923,"related":928,"readMore":-1,"target":932,"hasArticle":802},"gdpr","GDPR","Регламент ЕС о персональных данных людей в ЕС: законное основание для сбора, настоящее согласие на трекинг, право увидеть и удалить свои данные. Он следует за вашими пользователями, а не за вашими серверами: где зарегистрирована компания, значения не имеет.",[921,922],"Общий регламент по защите данных","General Data Protection Regulation",[924,926],{"kind":815,"url":925},"https:\u002F\u002Fgdpr.eu\u002F",{"kind":842,"url":927},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGeneral_Data_Protection_Regulation",[929,930,931],"pci-dss","soc-2","hipaa","\u002Fglossary#gdpr",{"slug":934,"term":935,"definition":936,"category":850,"aliases":937,"links":941,"related":944,"readMore":-1,"target":945,"hasArticle":802},"golden-test","Golden-тест","Тест, который отрисовывает виджет и сравнивает результат попиксельно с эталонным изображением. Во Flutter это самый дешёвый способ узнать, не сломал ли редизайн пустое состояние на 320pt, в тёмной теме, при 200% масштабе текста.",[938,939,940],"golden test","золотой тест","скриншотный тест",[942],{"kind":827,"url":943},"https:\u002F\u002Fapi.flutter.dev\u002Fflutter\u002Fflutter_test\u002FmatchesGoldenFile.html",[234],"\u002Fglossary#golden-test",{"slug":873,"term":947,"definition":948,"category":864,"aliases":949,"links":950,"related":955,"readMore":-1,"target":956,"hasArticle":802},"GraphQL","Язык запросов к API, где клиент сам перечисляет нужные поля и получает один ответ ровно такой формы. Он снимает избыточную выдачу, к которой дрейфуют REST-эндпоинты, и добавляет собственный режим отказа: неограниченный запрос, обходящий всю модель данных.",[],[951,953],{"kind":815,"url":952},"https:\u002F\u002Fgraphql.org\u002F",{"kind":842,"url":954},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGraphQL",[872],"\u002Fglossary#graphql",{"slug":931,"term":958,"definition":959,"category":850,"aliases":960,"links":962,"related":965,"readMore":-1,"target":966,"hasArticle":802},"HIPAA","Закон США о защищённой медицинской информации: как её можно хранить, передавать, логировать и раскрывать. Как и PCI-DSS, это архитектурное ограничение, которое выбирают в начале, а не документ, который дописывают перед запуском.",[961],"Health Insurance Portability and Accountability Act",[963],{"kind":842,"url":964},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHealth_Insurance_Portability_and_Accountability_Act",[929,917,930],"\u002Fglossary#hipaa",{"slug":968,"term":969,"definition":970,"category":864,"aliases":971,"links":974,"related":977,"readMore":-1,"target":979,"hasArticle":802},"headless-cms","Headless CMS","Система управления контентом с админкой и API, но без собственного фронтенда. Редакторы публикуют в одном месте, а сайт или приложение отрисовывает контент само — слой представления принадлежит вам, а не вендору CMS.",[972,973],"безголовая CMS","контентное API",[975],{"kind":842,"url":976},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHeadless_content_management_system",[978,872],"server-side-rendering","\u002Fglossary#headless-cms",{"slug":818,"term":981,"definition":982,"category":810,"aliases":983,"links":987,"related":990,"readMore":-1,"target":991,"hasArticle":802},"Host Card Emulation","Режим, в котором Android-телефон программно эмулирует бесконтактную карту по NFC, без аппаратного защищённого элемента. Так платит приложение-кошелёк на терминале: телефон говорит с ним по тому же протоколу EMV Contactless, что и пластиковая карта.",[984,985,986],"HCE","EMV Contactless","бесконтактные платежи",[988],{"kind":827,"url":989},"https:\u002F\u002Fdeveloper.android.com\u002Fdevelop\u002Fconnectivity\u002Fnfc\u002Fhce",[929,807],"\u002Fglossary#host-card-emulation",{"slug":993,"term":994,"definition":995,"category":810,"aliases":996,"links":997,"related":1000,"readMore":-1,"target":1002,"hasArticle":802},"impeller","Impeller","Движок рендеринга, на котором Flutter работает сегодня: по умолчанию на iOS с 2023 года и на Android с 2024-го. Он компилирует шейдеры заранее, а не во время первой анимации, что убрало главную видимую проблему Flutter в проде — джанк на компиляции шейдеров.",[],[998],{"kind":827,"url":999},"https:\u002F\u002Fdocs.flutter.dev\u002Fperf\u002Fimpeller",[1001],"skia","\u002Fglossary#impeller",{"slug":831,"term":1004,"definition":1005,"category":810,"aliases":1006,"links":1007,"related":1010,"readMore":-1,"target":1011,"hasArticle":802},"Install Referrer","API Google Play, который передаёт только что установленному Android-приложению параметры кампании из ссылки, приведшей к установке. Android-половина отложенного диплинкинга и надёжный способ понять, откуда пришёл пользователь.",[],[1008],{"kind":827,"url":1009},"https:\u002F\u002Fdeveloper.android.com\u002Fgoogle\u002Fplay\u002Finstallreferrer",[830,821],"\u002Fglossary#install-referrer",{"slug":1013,"term":1014,"definition":1015,"category":1016,"aliases":1017,"links":1019,"related":1024,"readMore":-1,"target":1025,"hasArticle":802},"jwt","JWT","Подписанный токен, несущий свои данные внутри: сервер понимает, кому принадлежит запрос, не обращаясь к хранилищу сессий. Стандарт мобильной аутентификации. Подпись доказывает, что токен не меняли, но не скрывает его содержимое.","protocol",[1018],"JSON Web Token",[1020,1022],{"kind":815,"url":1021},"https:\u002F\u002Fjwt.io\u002F",{"kind":842,"url":1023},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FJSON_Web_Token",[929],"\u002Fglossary#jwt",{"slug":1027,"term":1028,"definition":1029,"category":850,"aliases":1030,"links":1034,"related":1037,"readMore":-1,"target":1038,"hasArticle":802},"kyc","KYC","Know Your Customer — проверки личности, которые регулируемый финансовый продукт проводит, прежде чем разрешить переводить деньги: съёмка документов, liveness, санкционный и антиотмывочный скрининг. На онбординг это влияет сильнее любого дизайн-решения.",[1031,1032,1033],"Know Your Customer","AML","KYC\u002FAML",[1035],{"kind":842,"url":1036},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FKnow_your_customer",[929,917],"\u002Fglossary#kyc",{"slug":76,"term":74,"definition":1040,"category":810,"aliases":1041,"links":1043,"related":1044,"readMore":1045,"target":1045,"hasArticle":802},"Переиспользование бизнес-логики на Kotlin между Android, iOS и сервером, при этом интерфейс на каждой платформе остаётся нативным. Альтернатива Flutter, когда UI обязан быть нативным, а правила за ним — нет.",[1042],"KMP",[],[],"\u002Ftechnologies\u002Fkmp",{"slug":1047,"term":1048,"definition":1049,"category":1050,"aliases":1051,"links":1054,"related":1057,"readMore":-1,"target":1059,"hasArticle":802},"mvp","MVP","Минимальная версия продукта, которую можно показать реальным пользователям и которая при этом отвечает на вопрос, ради которого его делали. Решение об объёме, а не о качестве: MVP всё равно обязан работать.","business",[1052,1053],"минимально жизнеспособный продукт","minimum viable product",[1055],{"kind":842,"url":1056},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMinimum_viable_product",[1058],"white-label","\u002Fglossary#mvp",{"slug":1061,"term":1062,"definition":1063,"category":1016,"aliases":1064,"links":1068,"related":1073,"readMore":-1,"target":1074,"hasArticle":802},"oauth","OAuth","Стандарт, на котором держатся «Вход через Apple», Google и остальные: пользователь авторизует ваше приложение у провайдера, которому уже доверяет, а приложение получает токен вместо пароля. Никто не заводит новый пароль, и вы его не храните.",[1065,1066,1067],"OAuth 2.0","вход через соцсети","Sign in with Apple",[1069,1071],{"kind":815,"url":1070},"https:\u002F\u002Foauth.net\u002F2\u002F",{"kind":842,"url":1072},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOAuth",[1013],"\u002Fglossary#oauth",{"slug":929,"term":1076,"definition":1077,"category":850,"aliases":1078,"links":1081,"related":1086,"readMore":-1,"target":1087,"hasArticle":802},"PCI-DSS","Стандарт безопасности карточной индустрии, обязательный для всех, кто хранит, обрабатывает или передаёт данные карт. Большинство приложений намеренно остаются вне зоны его действия, отдавая ввод карты сертифицированному платёжному провайдеру.",[1079,1080],"PCI DSS","Payment Card Industry Data Security Standard",[1082,1084],{"kind":815,"url":1083},"https:\u002F\u002Fwww.pcisecuritystandards.org\u002F",{"kind":842,"url":1085},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPayment_Card_Industry_Data_Security_Standard",[1013],"\u002Fglossary#pci-dss",{"slug":1089,"term":1090,"definition":1091,"category":1050,"aliases":1092,"links":1095,"related":1098,"readMore":-1,"target":1100,"hasArticle":802},"product-market-fit","Product-market fit","Момент, когда продукт доказуемо нашёл своих людей: они им пользуются, возвращаются и платят. До него разработка отвечает на вопрос, после — на спрос.",[1093,1094],"PMF","соответствие продукта рынку",[1096],{"kind":842,"url":1097},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FProduct-market_fit",[1047,1099],"time-to-market","\u002Fglossary#product-market-fit",{"slug":1102,"term":1103,"definition":1104,"category":850,"aliases":1105,"links":1108,"related":1111,"readMore":-1,"target":1113,"hasArticle":802},"prompt-injection","Prompt injection","Атака, при которой текст от пользователя языковая модель читает как инструкции, а не как данные, и уходит в обход собственных правил. Родственник SQL-инъекции в эпоху LLM: возникает везде, где пользовательский ввод склеивается в промпт.",[1106,1107],"инъекция промпта","инъекция в промпт",[1109],{"kind":842,"url":1110},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPrompt_injection",[1112],"rate-limiting","\u002Fglossary#prompt-injection",{"slug":913,"term":1115,"definition":1116,"category":864,"aliases":1117,"links":1120,"related":1123,"readMore":-1,"target":1124,"hasArticle":802},"Pub\u002FSub","Шаблон обмена сообщениями: производитель публикует событие, а любое число потребителей независимо читает его через стоящий между ними брокер. Производитель никогда их не ждёт — так путь запроса остаётся быстрым, а более медленная работа выполняется в фоне.",[1118,1119],"публикация\u002Fподписка","Google Cloud Pub\u002FSub",[1121],{"kind":842,"url":1122},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPublish%E2%80%93subscribe_pattern",[],"\u002Fglossary#pub-sub",{"slug":872,"term":1126,"definition":1127,"category":864,"aliases":1128,"links":1131,"related":1134,"readMore":-1,"target":1135,"hasArticle":802},"REST","Общепринятый стиль HTTP-API: URL называет ресурс, а HTTP-метод говорит, что с ним сделать. Способ по умолчанию, которым приложение общается с бэкендом, и то, что ожидает найти большинство сторонних интеграций.",[1129,1130],"REST API","Representational State Transfer",[1132],{"kind":842,"url":1133},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FREST",[266,914],"\u002Fglossary#rest",{"slug":930,"term":1137,"definition":1138,"category":850,"aliases":1139,"links":1142,"related":1145,"readMore":-1,"target":1146,"hasArticle":802},"SOC 2","Отчёт внешнего аудитора о том, как компания обращается с данными клиентов — безопасность, доступность, конфиденциальность, — а не сертификат, который можно купить. Корпоративные заказчики его требуют, а архитектуру он ограничивает задолго до самого аудита.",[1140,1141],"SOC2","System and Organization Controls",[1143],{"kind":842,"url":1144},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSystem_and_Organization_Controls",[929,917,931],"\u002Fglossary#soc-2",{"slug":1148,"term":1149,"definition":1150,"category":1050,"aliases":1151,"links":1154,"related":1157,"readMore":-1,"target":1159,"hasArticle":802},"saas","SaaS","Софт, который продают как постоянную подписку на размещённый у поставщика продукт, а не как разовую лицензию для установки у себя. Поставщик держит серверы, непрерывно выкатывает обновления и берёт плату за пользователя или за объём.",[1152,1153],"Software as a Service","ПО как услуга",[1155],{"kind":842,"url":1156},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSoftware_as_a_service",[1158,1058],"multi-tenancy","\u002Fglossary#saas",{"slug":914,"term":1161,"definition":1162,"category":1016,"aliases":1163,"links":1165,"related":1168,"readMore":-1,"target":1169,"hasArticle":802},"Server-Sent Events","Односторонний поток от сервера к клиенту поверх обычного HTTP-соединения. Проще, чем WebSocket, и достаточен там, где только серверу есть что сказать: прогресс операции, ответ AI, приходящий токен за токеном.",[1164],"SSE",[1166],{"kind":842,"url":1167},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FServer-sent_events",[266,872],"\u002Fglossary#server-sent-events",{"slug":1001,"term":1171,"definition":1172,"category":810,"aliases":1173,"links":1176,"related":1181,"readMore":-1,"target":1182,"hasArticle":802},"Skia","Открытая 2D-графическая библиотека Google, которая рисует Chrome, Android и — до появления Impeller — каждый кадр Flutter. Она умеет выводить не только на экран, но и в PDF: именно это делает «печать в PDF» в Chrome.",[1174,1175],"Skia Graphics Engine","skia-safe",[1177,1179],{"kind":815,"url":1178},"https:\u002F\u002Fskia.org\u002F",{"kind":842,"url":1180},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSkia_Graphics_Engine",[993],"\u002Fglossary#skia",{"slug":1184,"term":1185,"definition":1186,"category":1050,"aliases":1187,"links":1191,"related":1192,"readMore":-1,"target":1194,"hasArticle":802},"staff-augmentation","Staff augmentation","Модель найма, при которой инженеры внешнего партнёра входят в вашу команду и работают под вашим управлением — в вашем репозитории, ваших спринтах, вашем процессе, — а не сдают отдельный проект. Вы покупаете ресурс; код и контекст остаются у вас.",[1188,1189,1190],"аутстаффинг","расширение команды","выделенные разработчики",[],[1193,1099],"total-cost-of-ownership","\u002Fglossary#staff-augmentation",{"slug":508,"term":509,"definition":1196,"category":1016,"aliases":1197,"links":1201,"related":1204,"readMore":-1,"target":1205,"hasArticle":802},"Слой шифрования под HTTPS. Он подтверждает, что сервер именно тот, о ком говорит его сертификат, согласует свежий ключ на сессию и шифрует всё дальнейшее — сеть между вами видит шифртекст и не может незаметно его изменить.",[1198,1199,1200],"SSL","HTTPS","Transport Layer Security",[1202],{"kind":842,"url":1203},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTransport_Layer_Security",[655,1013],"\u002Fglossary#tls",{"slug":1099,"term":1207,"definition":1208,"category":1050,"aliases":1209,"links":1212,"related":1215,"readMore":-1,"target":1216,"hasArticle":802},"Time to market","Время от решения строить продукт до момента, когда им пользуются настоящие люди. Большинство споров о стеке и объёме работ — на самом деле споры об этом числе: каждая сэкономленная неделя — это неделя выручки, обратной связи и позиции на рынке.",[1210,1211],"TTM","время выхода на рынок",[1213],{"kind":842,"url":1214},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTime_to_market",[1047,1193],"\u002Fglossary#time-to-market",{"slug":1218,"term":1219,"definition":1220,"category":1016,"aliases":1221,"links":1223,"related":1228,"readMore":-1,"target":1230,"hasArticle":802},"webrtc","WebRTC","Браузерный и мобильный стандарт для передачи аудио, видео и данных напрямую между двумя устройствами; серверы участвуют только в том, чтобы их познакомить. На нём строят видеозвонок внутри приложения, когда не берут готовый SDK.",[1222],"Web Real-Time Communication",[1224,1226],{"kind":815,"url":1225},"https:\u002F\u002Fwebrtc.org\u002F",{"kind":842,"url":1227},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWebRTC",[1229,266],"xmpp","\u002Fglossary#webrtc",{"slug":266,"term":267,"definition":1232,"category":1016,"aliases":1233,"links":1234,"related":1237,"readMore":-1,"target":1238,"hasArticle":802},"Протокол, который держит одно соединение между клиентом и сервером открытым, чтобы любая сторона могла отправить данные в любой момент, а не клиент спрашивал снова и снова. На нём работают живые котировки, чаты и статусы присутствия.",[],[1235],{"kind":842,"url":1236},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWebSocket",[914,872],"\u002Fglossary#websocket",{"slug":1058,"term":1240,"definition":1241,"category":1050,"aliases":1242,"links":1245,"related":1248,"readMore":1249,"target":1249,"hasArticle":781},"White-label","Один продукт, выпускаемый под многими брендами. White-label платформа собирает каждому клиенту готовое к публикации приложение со своим названием, оформлением и контентом из общей кодовой базы, а не форкает проект под заказчика.",[1243,1244],"белый лейбл","мультитенантное приложение",[1246],{"kind":842,"url":1247},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWhite-label_product",[1047],"\u002Fglossary\u002Fwhite-label",{"slug":1229,"term":1251,"definition":1252,"category":1016,"aliases":1253,"links":1256,"related":1261,"readMore":-1,"target":1262,"hasArticle":802},"XMPP","Открытый федеративный протокол обмена сообщениями и давняя альтернатива тому, чтобы писать чат-бэкенд самому или арендовать чужой. Он покрывает статусы присутствия, индикаторы набора и передачу файлов, а зрелые клиентские библиотеки есть под любую платформу.",[1254,1255],"Jabber","Extensible Messaging and Presence Protocol",[1257,1259],{"kind":815,"url":1258},"https:\u002F\u002Fxmpp.org\u002F",{"kind":842,"url":1260},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FXMPP",[1218,266],"\u002Fglossary#xmpp",{"slug":1264,"term":1265,"definition":1266,"category":1050,"aliases":1267,"links":1271,"related":1274,"readMore":-1,"target":1275,"hasArticle":802},"in-app-purchase","Встроенные покупки","Продажа цифровых товаров и подписок через биллинг Apple и Google, который оба стора требуют для цифрового контента и с которого берут комиссию. Сложность никогда не в самой покупке, а в её восстановлении на новом устройстве и в честном учёте прав доступа.",[1268,1269,1270],"in-app purchase","IAP","внутренние покупки",[1272],{"kind":827,"url":1273},"https:\u002F\u002Fdeveloper.apple.com\u002Fin-app-purchase\u002F",[1089],"\u002Fglossary#in-app-purchase",{"slug":830,"term":1277,"definition":1278,"category":810,"aliases":1279,"links":1284,"related":1287,"readMore":1288,"target":1288,"hasArticle":781},"Диплинкинг","Ссылка, которая открывает конкретный экран внутри установленного приложения, а не его главную или веб-страницу. Отложенный диплинкинг переживает установку: нажатие, прошедшее через магазин приложений, всё равно приводит на нужный экран.",[1280,1281,1282,1283],"deep linking","отложенный диплинкинг","Universal Links","Android App Links",[1285],{"kind":842,"url":1286},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMobile_deep_linking",[821,831],"\u002Fglossary\u002Fdeep-linking",{"slug":1290,"term":1291,"definition":1292,"category":864,"aliases":1293,"links":1297,"related":1300,"readMore":-1,"target":1301,"hasArticle":802},"multi-arch-image","Мультиархитектурный образ","Один тег образа, который разрешается в разные бинарники для каждой архитектуры процессора — обычно это пара linux\u002Famd64 и linux\u002Farm64, — так что один и тот же docker pull работает без изменений и на серверах Intel\u002FAMD, и на ноутбуках с Apple Silicon.",[1294,1295,1296],"мультиарх-сборка","multi-arch build","linux\u002Famd64 + linux\u002Farm64",[1298],{"kind":827,"url":1299},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-platform\u002F",[889],"\u002Fglossary#multi-arch-image",{"slug":1158,"term":1303,"definition":1304,"category":864,"aliases":1305,"links":1308,"related":1311,"readMore":-1,"target":1313,"hasArticle":802},"Мультитенантность","Один развёрнутый бэкенд обслуживает много клиентов, и каждый видит только свои данные, конфигурацию и включённые функции, потому что контекст тенанта определяется для каждого запроса. Именно это делает линейку брендированных приложений одним продуктом, а не набором форков.",[1158,1306,1307],"мультиарендность","тенант",[1309],{"kind":842,"url":1310},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitenancy",[1058,1312],"feature-flags","\u002Fglossary#multi-tenancy",{"slug":845,"term":1315,"definition":1316,"category":864,"aliases":1317,"links":1321,"related":1324,"readMore":-1,"target":1325,"hasArticle":802},"Объектное хранилище","Хранилище, которое держит файл целиком под ключом, а не в дереве файловой системы, — Amazon S3 и множество сервисов, совместимых с его API. Дешёвое, практически безграничное, привычное место для сырых событий, бэкапов и медиа: пишется один раз, читается редко, хранится вечно.",[1318,1319,1320],"S3","S3-совместимое хранилище","блоб-хранилище",[1322],{"kind":842,"url":1323},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FObject_storage",[834],"\u002Fglossary#object-storage",{"slug":1112,"term":1327,"definition":1328,"category":850,"aliases":1329,"links":1333,"related":1336,"readMore":-1,"target":1337,"hasArticle":802},"Ограничение частоты запросов","Предел на число запросов от одного клиента за заданный интервал. Именно он не даёт одному увлечённому пользователю, скраперу или боту потратить месячный бюджет платного API за вечер, и стоять он должен на вашей стороне интеграции.",[1330,1331,1332],"rate limiting","рейт-лимит","троттлинг",[1334],{"kind":842,"url":1335},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRate_limiting",[1102],"\u002Fglossary#rate-limiting",{"slug":1339,"term":1340,"definition":1341,"category":810,"aliases":1342,"links":1345,"related":1348,"readMore":-1,"target":1349,"hasArticle":802},"platform-channels","Платформенные каналы","Мост, через который Flutter-приложение вызывает нативный код iOS и Android — Keychain и Keystore, биометрию, платёжные шторки, любой SDK без Dart-пакета. Работа рутинная, но настоящая, и первое место, где споткнётся инженер, не выходивший за пределы Dart.",[1343,1344],"platform channels","method channel",[1346],{"kind":827,"url":1347},"https:\u002F\u002Fdocs.flutter.dev\u002Fplatform-integration\u002Fplatform-channels",[76],"\u002Fglossary#platform-channels",{"slug":1351,"term":1352,"definition":1353,"category":1016,"aliases":1354,"links":1357,"related":1360,"readMore":-1,"target":1361,"hasArticle":802},"post-quantum-cryptography","Постквантовая криптография","Алгоритмы шифрования, рассчитанные на устойчивость к будущему квантовому компьютеру; стандарты уже финализированы NIST. Мигрировать нужно до появления железа: трафик, записанный сегодня, расшифруют, когда такая машина появится.",[1355,1356],"PQC","постквантовое шифрование",[1358],{"kind":842,"url":1359},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPost-quantum_cryptography",[508,655],"\u002Fglossary#post-quantum-cryptography",{"slug":1363,"term":1364,"definition":1365,"category":850,"aliases":1366,"links":1370,"related":1371,"readMore":-1,"target":1372,"hasArticle":802},"staged-rollout","Поэтапная раскатка","Релиз сначала на небольшой процент пользователей и расширение только тогда, когда доля сессий без падений держится. Плохая сборка, пойманная на десяти процентах, — испорченный вечер; она же на ста процентах — испорченная неделя.",[1367,1368,1369],"staged rollout","phased release","канареечный релиз",[],[1312,234],"\u002Fglossary#staged-rollout",{"slug":889,"term":1374,"definition":1375,"category":864,"aliases":1376,"links":1382,"related":1385,"readMore":-1,"target":1386,"hasArticle":802},"Реестр контейнеров","Хранилище образов контейнеров, адресуемых по имени и тегу, — Docker Hub, GitHub Container Registry или собственный реестр облачного провайдера. Публикация сборки в реестр превращает «у меня работает» в образ, который любой может скачать и запустить без изменений.",[1377,1378,1379,1380,1381],"реестр образов","Docker registry","GHCR","ghcr.io","container registry",[1383],{"kind":827,"url":1384},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Fpackages\u002Fworking-with-a-github-packages-registry\u002Fworking-with-the-container-registry",[876,1290],"\u002Fglossary#container-registry",{"slug":978,"term":1388,"definition":1389,"category":864,"aliases":1390,"links":1393,"related":1396,"readMore":-1,"target":1397,"hasArticle":802},"Серверный рендеринг","Сборка страницы в готовый HTML на сервере, чтобы первый же ответ содержал контент, заголовки, метатеги и структурированные данные. Краулеры, превью ссылок и медленные устройства читают это, не выполняя JavaScript.",[1391,1392],"SSR","server-side rendering",[1394],{"kind":842,"url":1395},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FServer-side_scripting",[968],"\u002Fglossary#server-side-rendering",{"slug":655,"term":643,"definition":1399,"category":864,"aliases":1400,"links":1404,"related":1407,"readMore":-1,"target":1408,"hasArticle":802},"Шифрование, которое накладывается на устройстве отправителя и снимается только на устройстве получателя, так что сервис, передающий сообщение, не может его прочитать — ни по решению суда, ни после взлома. Оно защищает содержимое, но никогда — метаданные.",[1401,1402,1403],"E2EE","end-to-end encryption","оконечное шифрование",[1405],{"kind":842,"url":1406},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FEnd-to-end_encryption",[508,1013],"\u002Fglossary#end-to-end-encryption",{"slug":1193,"term":1410,"definition":1411,"category":1050,"aliases":1412,"links":1415,"related":1418,"readMore":-1,"target":1419,"hasArticle":802},"Совокупная стоимость владения","Во что продукт обходится за всю жизнь, а не только на этапе разработки: поддержка, обновления, ежегодные миграции на новые ОС и правила сторов, вторая команда, чтобы две кодовые базы не расходились. Обычно больше сметы на разработку и почти никогда в неё не входит.",[1413,1414],"TCO","total cost of ownership",[1416],{"kind":842,"url":1417},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTotal_cost_of_ownership",[1099],"\u002Fglossary#total-cost-of-ownership",{"slug":1421,"term":1422,"definition":1423,"category":864,"aliases":1424,"links":1428,"related":1431,"readMore":-1,"target":1432,"hasArticle":802},"state-management","Управление состоянием","То, как приложение решает, где живёт значение, кому позволено его менять и какие части экрана перерисовываются, когда оно меняется. Во Flutter выбор между Riverpod, BLoC и Provider — одно из первых архитектурных решений и одно из самых трудных для пересмотра.",[1425,1426,1427],"state management","BLoC","Riverpod",[1429],{"kind":827,"url":1430},"https:\u002F\u002Fdocs.flutter.dev\u002Fdata-and-backend\u002Fstate-mgmt\u002Foptions",[934],"\u002Fglossary#state-management",{"slug":1312,"term":1434,"definition":1435,"category":850,"aliases":1436,"links":1440,"related":1443,"readMore":-1,"target":1444,"hasArticle":802},"Фиче-флаги","Переключатели, которые включают и выключают функциональность из конфигурации, а не из релиза. Один бинарник ведёт себя по-разному для разных брендов, рынков и пользователей, а рискованную фичу можно погасить, не отправляя новую сборку на ревью.",[1437,1438,1439],"feature flags","фиче-флаги","feature toggle",[1441],{"kind":842,"url":1442},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFeature_toggle",[1363,1058,1158],"\u002Fglossary#feature-flags",{"slug":1446,"term":1447,"definition":1448,"category":864,"aliases":1449,"links":1453,"related":1456,"readMore":-1,"target":1457,"hasArticle":802},"floating-point","Числа с плавающей точкой","Двоичный формат IEEE 754, стоящий за double и float. Он не хранит 0.1 точно, поэтому 0.1 + 0.2 даёт 0.30000000000000004 — незаметно в графике и фатально в деньгах, которым место в целых минорных единицах или в decimal-типе.",[1450,1451,1452],"IEEE 754","double","плавающая запятая",[1454],{"kind":842,"url":1455},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FIEEE_754",[],"\u002Fglossary#floating-point"]