Мобільне · приватність

Kyndsy — приватний тренер мовлення й поведінки для iOS та Android

Мобільний застосунок чує голос свого власника і рахує грубі вислови, ввічливі, слова-паразити та різкий тон — тридцятьма мовами, включно зі змішаним мовленням. Розбір іде на пристрої: звук не зберігається, розшифровка не пишеться, облікового запису та імені немає взагалі. Ми зробили продукт цілком — застосунок, вміст тридцятьма мовами, легкий сервер і сайт.

Категорія
Мобільне · приватність
Оцінка вартості
від €26 000
Терміни
≈ 12–16 тижнів
kyndsy.app
Kyndsy
Сайт проєкту — kyndsy.app

01Огляд проєкту

Kyndsy — мобільний застосунок, що відповідає на питання, на яке майже ніхто не може відповісти про себе сам: як я насправді говорю? Він чує голос власника у звичайній розмові й рахує грубі вислови, ввічливі, слова-паразити та моменти, коли тон стає різким. Показує динаміку по днях і тижнях. І на цьому зупиняється — він не каже людині, якою людиною її це робить.

Задум у тому, що застосунки для саморозвитку здебільшого малюють графік вашої ж думки. Ви звітуєте про день, вони візуалізують звіт. Kyndsy починає з того, з чим складніше сперечатися: зі слів, які справді були сказані, порахованих, поки людина була зайнята життям, а не сіла рефлексувати.

Це ж робить продукт важким. Рахувати мовлення означає ввімкнути мікрофон, а мікрофон означає, що людина має довіряти застосунку більше, ніж майже всьому іншому в телефоні. Тому весь продукт побудований навколо обіцянки, яка зобов'язана бути будовою, а не текстом: звук не зберігається, слова не записуються, чужі голоси не розбираються, і немає облікового запису, до якого все це можна було б прив'язати.

Ми зробили все: застосунок для iOS та Android, вміст тридцятьма мовами, легкий сервер, шлях випуску в магазини й сайт продукту. Нижче — завдання, рішення і те, що ми свідомо відмовилися робити.

02Контекст і завдання

Застосунок, який слухає, — це галузь, де очевидна реалізація водночас неправильна. Розбір завдання дав набір обмежень, які визначили все подальше.

  • Довіра і є продукт. У застосунку, що вимірює мовлення, рівно один актив, і це не алгоритм. Якщо людина запідозрить, що звук іде з телефона, точність не врятує — вона видалить застосунок.
  • Оточення ні на що не погоджувалося. Мікрофон у кімнаті чує всіх, хто в ній є. Розбір мовлення людей навколо власника — це інший застосунок, і значно гірший.
  • Число про людину небезпечне. Будь-яка єдина оцінка, що претендує описати людину, — твердження, якого продукт не може чесно зробити; і її прочитають як вирок, хоч би що було написано поруч дрібним шрифтом.
  • Сирі лічильники брешуть. «Ви вилаялися дев'ять разів» заохочує мовчання: той, хто нічого не казав, має вигляд людини, яка виправилася.
  • Слова неоднозначні. Те саме слово — жарт, цитата, скарга на себе чи справжня образа, залежно від тону й контексту. Рахунок за рядком дає числа, у яких ніхто не впізнає свого дня.
  • Люди говорять не однією мовою. Вони перемикаються посеред фрази. Лічильник, що йде лише за однією мовою, відзвітує підозріло спокійним днем щоразу, коли власник перейшов на іншу.
  • У магазинів є правила про мікрофон, про твердження щодо здоров'я та психології і про те, що взагалі може закривати підписка, — і перевіряються вони на поданні, а не в день запуску.

Усе це мало працювати на телефоні, у фоні, не з'їдаючи ні батареї, ні терпіння людини.

03Цілі проєкту

  • Рахувати мовлення на пристрої. Розбір іде на телефоні; звук не зберігається і не вивантажується.
  • Тільки голос власника. Чужі голоси відкидаються, а не розбираються, і режиму «спрямувати застосунок на іншу людину» не існує.
  • Ані облікового запису, ані імені. Витікати нічому, бо збирати нічого.
  • Частки, а не сирі лічильники. Усе на тисячу сказаних слів, щоб тихий день лишався тихим днем, а не досягненням.
  • Тридцять мов, включно зі змішаним мовленням — словники мають існувати в усіх одразу, інакше число бреше тим, хто перемикається.
  • Розрізняти відтінки. Іронія, сарказм, жарт і справжня різкість розведені й позначені як здогад, а не як вирок.
  • Корисно й без мікрофона. Щоденник, компас цінностей, тести й вечірні питання працюють самі по собі.
  • Мотивація, яку не можна обіграти. Серії, рівні та програми оцінюються вимірюванням, а не відкриттям застосунку.
  • Жодної загальної оцінки людини. Ані в першій версії, ані потім.

04Що ми зробили

Застосунок улаштований як чотири місця, кожне відповідає на своє питання, плюс те, що їх тримає:

  • Сьогодні — що щойно було: показник мовлення, цілі дня і одна підказка, а не список із шести.
  • Прогрес — чи йде це кудись: серії, рівні, програми і тижневий звіт.
  • Компас — на що людина вирішила орієнтуватися: три-п'ять цінностей, обраних нею самою, і рух до них.
  • Ви — усе, що належить лише їй: тести самоперевірки, сімейний доступ, свої дані й підтримка.

Знизу лежить те, що робить ці чотири місця чесними: розбір мовлення на пристрої, словники й правила для тридцяти мов, визначення відтінків, модель рахунку в частках, а не в підсумках, легкий сервер, який майже нічого не знає, і реєстр налаштувань, що дозволяє змінювати продукт без випуску в магазині.

05Приватність — це код, а не текст

Обіцянки приватності на сайті — не рекламний текст, який наступна оптимізація може тихо зробити неправдою. Це властивості збірки, і правка, що робить будь-яку з них хибною, вважається в проєкті дефектом, а не розміном.

  • Звук нікуди не пишеться — ані у файл, ані у тимчасовий буфер на диску, ані в журнал. І у зневаджувальній збірці теж, бо саме так такі речі й витікають.
  • Розбирається лише голос власника. Чуже мовлення відкидається до того, як із нього вийдуть слова.
  • Розшифровки немає. Застосунок виробляє лічильники, а не текст; немає збереженої фрази, яку можна було б отримати на запит або випадково синхронізувати.
  • Сесію запускає лише людина. Ані автозапуску після перезавантаження, ані тихого відновлення у фоні.
  • Голосовий профіль не покидає телефон і виключений із резервних копій — це біометричні дані, а копія якраз те місце, про яке забувають.
  • Серверу кажуть чотири речі й не більше: запит налаштувань, разове завантаження моделей, звернення до підтримки, якщо людина сама його написала, і чек підписки. Облікового запису немає.
  • Людина — це пара випадкових чисел, вигаданих її ж телефоном. Ми їх не видаємо і не рахуємо — а отже, не знаємо кількості встановлень, і це була свідома ціна.
  • Вхід необов'язковий і нічого не відкриває. Він потрібен, щоб перенести підписку й історію на новий телефон. Обов'язковий вхід створив би зв'язок зі справжнім обліковим записом там, де його зараз немає.

На останньому пункті варто затриматися. Вимога власника була — знати лише анонімний ідентифікатор, і спокусливий спосіб її виконати це обов'язковий вхід, який ми потім обіцяємо не читати. Ми зробили навпаки: облікового запису немає взагалі, а необов'язковий вхід читає з токена рівно одне поле й зберігає його хешем.

06Що саме рахує застосунок

Чотири речі: грубі вислови, ввічливі вислови, слова-паразити та піднятий, різкий тон. Усе це показується на тисячу сказаних слів, а не сирим підсумком: сирий лічильник робить мовчання схожим на прогрес, а застосунок, який нагороджує власника за те, що він мовчав, не зрозумів власної роботи.

Заголовок дня — індекс шанобливого мовлення, і правила навколо нього продумані не менше за саме число:

  • Він повністю прихований, поки не почуто п'ятдесяти слів. Нуль у тихий ранок читається як звинувачення, а не як відсутність даних.
  • Дні, де слів менше за п'ятдесят, показуються, але не рахуються — видні порожніми, а не вдають хороший день.
  • Ввічливість піднімає індекс не більш як на десять пунктів. Далі показник було б дешевше набрати люб'язностями, ніж заробити відсутністю різкості.
  • Будь-яку подію можна позначити як помилкову, і це змінює число, а не просто викреслює рядок зі списку.

Види поверх цього звичайні за формою і уважні в дрібницях: тижневий тренд, картина дня по годинах, тридцятиденна сітка по квадрату на день. Годинний вид відмовляється оголошувати «найгіршу годину», поки в нього немає десяти подій; тридцятиденна сітка лишає тихі дні бежевими, а не фарбує їх у спокійні. Графіки, впевнені на тонких даних, — це спосіб, яким продукт-вимірювач втрачає довіру читача, зазвичай назавжди.

07Відтінки мовлення: іронія, жарт, укол

Жарт і образа — не те саме слово двічі. Kyndsy відділяє іронію від справжньої різкості, жарт від уколу, цитату від того, що людина мала на увазі, — і показує словами, що йому почулося, поруч із подією.

Чесність цієї функції тримають два правила. Перше: це здогад, а не вирок — застосунок пише «можливо, іронія» або «жарт — не зараховано» і показує, на чому ґрунтувався. Друге, і важливіше: відтінок ніколи не рухає індекс. Він повідомляє людині, але не підкручує її показник мовчки. Число, зважене за впевненістю, ніхто не зміг би перевірити, і воно швидко стало б найспірнішою функцією продукту.

Так само акуратно влаштований контекст: те саме слово рахується по-різному, коли людина когось цитує, говорить про себе або перебуває посеред суперечки. А оскільки жоден словник не знає, що чиїсь слова означають особисто для неї, у людини є власні списки.

08Тридцять мов — і змішане мовлення

Застосунок працює тридцятьма мовами — англійська, іспанська, португальська, німецька, французька, італійська, нідерландська, шведська, данська, норвезька, фінська, польська, чеська, хорватська, румунська, угорська, грецька, турецька, російська, українська, білоруська, іврит, арабська, гінді, індонезійська, в'єтнамська, тайська, китайська, японська і корейська — і кількома одразу, бо дуже багато людей саме так і говорять.

Тридцять мов — це не тридцять перекладів інтерфейсу. Це тридцять наборів словників (грубі вислови, ввічливі звороти, паразити), і з'являтися вони зобов'язані одночасно. Мова з недоробленим словником не падає гучно — вона звітує спокійним днем. Людина бачить хороше число і вірить йому, а це гірше за повідомлення про помилку.

Один урок цього проєкту виходить далеко за його межі: ознака, вгадана за виглядом тексту, ламається на першій же мові з іншою писемністю. Вважати «зворотом» рядок із пробілом працює рівно до японської, китайської й тайської, які пишуться без пробілів, — і там застосунок не знаходить нічого, мовчки, продовжуючи мати вигляд працюючого. Поведінка мови має братися з даних самої мови, і вона зобов'язана бути закрита тестом одразу по всіх тридцяти.

09Компас і щоденник

Мовлення — лише половина продукту. Друга половина — те, на що людина вирішила орієнтуватися: вона обирає три-п'ять цінностей із семи (повага, чесність, самовладання, відповідальність, турбота, справедливість, надійність), і застосунок показує рух до них, а не до чийогось чужого уявлення про хорошу людину.

Рух складається з двох джерел: вимірювань мовлення і власного щоденника вчинків — дотримав обіцянку, вибачився, зірвався, виправив. Плюс три питання наприкінці дня, коли вони потрібні.

Загальної оцінки моральності немає — ані зараз, ані потім. Це єдине, що продукт відмовляється обчислювати. І саме тому компас працює: чесні цінності людина обере лише для застосунку, який не збирається ставити їй за них оцінку.

Усе в цій половині працює без мікрофона. Щоденник, компас, тести й вечірні питання стоять самі по собі, тож голосову частину можна налаштувати пізніше або ніколи — і застосунок усе одно лишиться корисним. Це продуктове рішення зі справжніми наслідками для утримання, і ми ухвалили б його знову: запит дозволу на першому екрані — те місце, де застосунок про приватність втрачає тих, заради кого його писали.

10Програми, серії та тижневий звіт

Мотивація тут зобов'язана була бути несприйнятливою до двох звичних обходів: часто відкривати застосунок і нічого не говорити. Тому:

  • Програми тривають від 7 до 30 днів з однією метою й одним числом — тиждень без грубих слів, м'якше відповідати два тижні, менше паразитів за місяць. Спрацювало чи ні, вирішують вимірювання, а не галочка.
  • Серія рахує дні, у які людина справді втримала рівень. Тихі дні її не рвуть і не продовжують — прибрати телефон не спосіб виграти.
  • Рівні заробляються днями, а не відкриттями застосунку: Спостереження, Контроль, Спокійне мовлення.
  • Щити закривають зрив, але не безмежно, а зірваний день можна викупити — тільки серія з тридцяти днів, чотири з яких куплені, це не серія з тридцяти днів, тому такі дні рахуються й показуються окремо.
  • Тижневий звіт прямо каже, коли порівнювати немає з чим. Зведення, у якому завжди щось покращилося, перестає читатися до третього тижня.

Варто назвати одну навмисну асиметрію: безкоштовний рівень обмежує показ історії, а не рахунок. Рахувати серію лише за видимим вікном означало б показувати тридцятиденну серію як семиденну — це не обмеження безкоштовного тарифу, а неправда про людину.

11Сто тестів самоперевірки

Поруч із вимірюваннями лежить сотня структурованих тестів самоперевірки: по двадцять п'ять тверджень, близько чотирьох хвилин, п'ять граней оцінюються окремо, тому відповідь ніколи не зводиться до одного плаского числа. Теми — мовлення, почуття, близькі, робота, ви самі, звички і життя в мережі.

Це явно не діагнози й не вимірювання особистості — це структурована саморефлексія, і застосунок каже про це там, де людина прочитає, а не в налаштуваннях. Відповіді лишаються на телефоні, як і все інше.

Інженерний сенс тут у тому, що сотню тестів не можна вести як сотню написаних руками екранів. Вони лежать ресурсом, а не кодом: збираються з джерел, перевіряються на збірці й відкидаються, якщо в тесту немає повного набору тверджень і граней. Саме ця перевірка робить можливим мати їх сто, і вона ж дозволила роздати правила відкриття однаково, а не розставити руками.

Половина відкривається працею, половина купується. Товарів під платну половину навмисне небагато, а не по одному на тест: сотню позицій у магазинах ніхто не заведе руками і ніхто не перекладе тридцятьма мовами. Продається відкриття; який саме тест на нього витратити, людина обирає в застосунку вже після підтвердження покупки.

12Підписка, сім'я та магазини

Платний рівень — підписка, і сім'я її ділить: шість місць на рік, включно з місцем покупця. Важливо, що саме ділить сім'я і чого не ділить: сім'я ділить право, а не дані. Ніхто не бачить чужих чисел, подій і щоденника, а той, хто оплатив, бачить вільні місця й дати, а не те, хто їх зайняв.

Це не застереження дрібним шрифтом, а будова: чужих показників на сервері немає взагалі, тому в сімейному екрані нема чого випадково розкрити. Вводячи код, людина погоджується розділити підписку, а не назватися.

Два правила з цієї частини пережили саму функцію. Перше: підписка й сімейне право — один прапорець у застосунку; друге питання на кшталт «а може, він у сім'ї» забули б рівно там, де воно важливе. Друге: мовчання сервера право не знімає — мережа зникає значно частіше, ніж закінчується підписка, і застосунок, що замикає платящу людину в потязі, зробив очевидний вибір погано.

Правила магазинів визначили тут багато що: що має право стверджувати застосунок із мікрофоном, як можна показувати платний рівень і те, що зламану збірку не відкотиш хотфіксом. Тому політика версій — мінімальна підтримувана версія, вимога оновитися, режим обслуговування і текст повідомлення всіма мовами проєкту одразу — це серверне налаштування, а не те, що вкомпільоване всередину.

13Архітектура: застосунок, сервер, реєстр

Архітектура випливає з обіцянки приватності: якомога більше на телефоні, якомога менше на сервері.

  • Застосунок веде розбір, зберігає історію і володіє голосовим профілем. Він і є продукт; сервер тут на підхваті.
  • Легкий сервер відповідає на чотири види запитів — налаштування, разове завантаження моделей, звернення до підтримки і чеки підписки. Таблиці користувачів у нього немає, бо немає користувачів, яких туди класти.
  • Реєстр налаштувань тримає те, що інакше було б зашите в застосунок: ідентифікатор пакета, адресу API, параметри входу, список мов, прапорці функцій і політику версій. Значення не пишуться у джерела руками, а генеруються в них, і згенерований файл позначено «не правити» з простої причини: ручна правка губиться при наступній генерації.
  • Передпольотна перевірка стоїть гейтом перед кожною збіркою: вона відмовляє, якщо ідентифікатор пакета розійшовся з реєстром, якщо версія не вища за зібрану, якщо сервер застосунку не відповідає, якщо словник неповний хоч однією мовою проєкту, якщо статичний аналіз не чистий, якщо падають тести або якщо в джерелах знайшлося схоже на ключ. Вона повертає ненульовий код, тому годиться гейтом у будь-якому CI.
  • Платний рівень стоїть за прапорцем, який гаситься без перезбирання і без нової версії в магазині.

Сайт — невеликий PHP-застосунок без власної бази, окрім листування підтримки: той самий принцип, застосований на рівень вище.

14Технологічний стек

  • Flutter для iOS та Android з одного коду — з дизайн-системою в коді, щоб колір, відступ і заокруглення задавалися в одному місці, а не в кожного віджета.
  • Розпізнавання мовлення й розбір на пристрої: моделі завантажуються один раз і працюють локально, а маніфест з їхніми розмірами й хешами будується з файлів, а не пишеться руками.
  • PHP 8.4 для сервера застосунку й сайту, з невеликою базою лише під листування підтримки.
  • Реєстр налаштувань як джерело істини для параметрів застосунку, з генерацією коду і передпольотним гейтом.
  • Тридцять мовних наборів у застосунку і три на сайті, з паритетом словників, який тримають тести, а не рев'ю.
  • Сувора політика безпеки вмісту на сайті — жодного інлайнового стилю, обчислювані значення збираються в окрему таблицю стилів, шрифт свій: сторінка про приватність не тягне жодного чужого ресурсу.

15Дизайн і UX

Візуальна мова — одна темна тема, знята з сайту продукту, щоб людина відкривала рівно те, що їй обіцяли. Світлий варіант написаний у токенах і навмисне не підключений: дві теми означають два набори знімків і вдвічі більше місць, де верстка ламається непомітно.

Колір, відступ і заокруглення живуть в одному файлі дизайну, а перехід із тривожного кольору в спокійний іде через теплий жовтий: навпростець середина дає оливкову бруднь — те, що має вигляд недбалості, а насправді є пропущеною опорною точкою.

У застосунку є персонаж, і правила навколо нього не так про чарівність, як про чесність: настрій читається силуетом, а не лише кольором, тому дальтонік бачить те саме, що всі; настрій — неперервна шкала з анімацією між значеннями, а не п'ять готових картинок, бо стрибок читається як інша картинка, а не як той самий герой; а при тривозі брови йдуть внутрішніми кінцями вгору, бо опущені всередину — це злість на того, хто дивиться.

В усьому іншому інтерфейс дотримується головного правила продукту: показувати виміряне, казати вголос, коли сказати нема чого, і ніколи не зводити людину до одного числа.

16Як ми працювали

  • Спочатку обіцянка. Ми записали, чого застосунок не робитиме ніколи — зберігати звук, розбирати оточення, питати, хто ви, оцінювати вас як людину, — до всякого проєктування: ці рішення обмежують архітектуру, а не випливають із неї.
  • Ядро вимірювання. Розбір на пристрої, рахунок у частках, індекс із його порогами й відмовою з'являтися на тонких даних.
  • Мовна робота. Тридцять словників і правил, з паритетом, закритим тестами одразу по всіх.
  • Друга половина. Компас, щоденник, програми, серії, тижневий звіт — усе, що працює без мікрофона.
  • Тести як ресурс. Сотня тестів самоперевірки, які збираються й перевіряються, з драбиною відкриття, яку роздає збирач.
  • Монетизація. Підписка, сім'я, невеликий набір товарів у магазинах і платний рівень за прапорцем.
  • Шлях випуску. Реєстр, генерована конфігурація, передпольотний гейт, реєстрація збірок і політика версій.
  • Сайт. Три мови, сувора політика безпеки вмісту і лендинг, що показує справжні екрани застосунку.

Дві речі поверталися під час роботи постійно, і обидві стали правилами. Усе, що інтерфейс стверджує про поведінку людини, зобов'язане перевірятися вимірюванням; усе, що застосунок обіцяє про приватність, зобов'язане триматися кодом, а не нотаткою в документі — домовленість живе рівно до наступного, хто її не прочитав.

17Результат

Вийшов вимірювальний продукт для того, про що зазвичай лише здогадуються, — влаштований так, що вимірювання не коштує людині приватності.

30
мов, включно зі змішаним мовленням
0
збереженого звуку, розшифровок і облікових записів
100
структурованих тестів самоперевірки
  • Розбір мовлення на пристрої: нічого не записується, нічого не розшифровується, чужі голоси відкидаються.
  • Усе показується на тисячу слів, тому мовчання не сприймають за прогрес.
  • Іронія, сарказм і жарти розведені — і позначені як здогад, що не рухає показника.
  • Тридцять мов зі словниками, які з'являються одночасно, і тестами одразу по всіх.
  • Компас цінностей, щоденник, програми і тижневий звіт, який визнає, коли порівнювати немає з чим.
  • Сотня тестів як перевірювані ресурси і невеликий підтримуваний набір товарів під платну половину.
  • Сімейний тариф, який ділить підписку і нічого більше — бо даних на сервері немає.

18Висновки

Kyndsy — проєкт, де найважча інженерія була в обмеженнях. Розбір на пристрої, відсутність розшифровки, відсутність облікового запису, відмова від загальної оцінки, відмова розбирати оточення — кожне з них ускладнювало збірку і робило продукт можливим. Версія цього застосунку із серверним конвеєром і логіном писалася б швидше і не заслуговувала б на чийсь мікрофон.

Урок, який ми забираємо, — про те, як тримаються обіцянки: гарантія, що живе в документі, — гарантія рівно до наступної правки, яку з нею не звірили. Тут витримали ті, що виражені кодом і закриті тестами: паритет по тридцяти мовах, контраст, перевірюваний числом, а не поглядом, рух, перевірюваний значеннями, а не знімком, і гейт збірки, який відмовляє, а не попереджає.

Якщо ви робите мобільний продукт, де приватність — це функція, а не застереження; щось, що зобов'язане працювати одразу багатьма мовами; або застосунок, числам якого люди мають вірити про себе, — таку роботу ми ведемо від задуму до магазину.