diff --git a/personal/projects/psychologist-app/analytics.md b/personal/projects/psychologist-app/analytics.md new file mode 100644 index 00000000..fbe15899 --- /dev/null +++ b/personal/projects/psychologist-app/analytics.md @@ -0,0 +1,137 @@ +--- +created: '2026-05-19' +updated: '2026-05-19' +tags: + - project + - app + - psychology + - analytics + - privacy +--- +# Analytics — Privacy-First + +> Stage 1: понять воронку и аудиторию без Google Analytics и без нарушения GDPR. +> Связан с: [[privacy-legal]], [[onboarding-ux]] + +--- + +## Принципы + +1. **Никакого Google Analytics** — Google = третья сторона, data sharing, GDPR nightmare для mental health data +2. **Анонимность по умолчанию** — никаких идентифицирующих данных в аналитике +3. **Прозрачность** — пользователь видит что собирается, может отключить +4. **Self-hosted или privacy-first SaaS** — данные не уходят в рекламные экосистемы + +--- + +## Что собирать (Stage 1) + +### Демография (при онбординге, анонимно) + +| Поле | Формат | GDPR | +|------|--------|------| +| Пол | male / female / other / prefer_not | Не PII если без связки с ID | +| Возраст | bucket: 18-24 / 25-34 / 35-44 / 45+ | Не PII | +| Страна | ISO код: RU / KZ / KG / US | Не PII | +| Семейный статус | single / relationship / married / other | Не PII | +| Занятость | employed / self / student / unemployed / other | Не PII | + +**Как сделать GDPR-совместимо**: +- Собирать как агрегированные bucket'ы, не точные значения +- Хранить отдельно от user_id (разные таблицы, разные ключи) +- Лучше: хранить только в агрегированных счётчиках — никакой строки на пользователя вообще +- Указать в Privacy Policy и на экране онбординга + +### Продуктовые метрики (поведенческие, анонимные) + +**Воронка онбординга**: +- Установил → открыл анкету → завершил анкету → дошёл до диалога → зарегистрировался → подписался + +**Активность**: +- DAU / MAU (считать по анонимным session токенам, не user_id) +- Среднее число сессий в неделю +- Средняя длина сессии (в мин) +- Churn: не открывал N дней (когортный анализ) +- Retention D1, D7, D30 + +**Сессии**: +- Завершена / брошена / частичная +- На каком шаге бросают (без содержимого ответов — только step index) +- Время между сессиями + +--- + +## Инструменты + +### Self-hosted (рекомендовано) + +**PostHog** (self-hosted на Fly.io / VPS) +- Open source, GDPR-friendly, EU data residency +- Product analytics: фunnels, cohorts, retention, DAU/MAU +- Feature flags (нужны будут для A/B) +- Self-hosted = данные не уходят никуда +- Fly.io: ~$5-10/мес за инстанс + +**Plausible** (self-hosted или EU cloud, $9/мес) +- Легче чем PostHog, только web/product metrics +- Без cookies, GDPR-compliant by design +- Если нужна только базовая воронка — достаточно + +### Privacy-first SaaS (если не хочется поднимать инфраструктуру) + +| Сервис | Цена | Плюсы | +|--------|------|-------| +| **PostHog Cloud (EU)** | Бесплатно до 1M events | EU серверы, GDPR, self-serve | +| **Plausible Cloud** | $9/мес | Простота, no cookies | +| **Mixpanel** | Бесплатно до 20K users | Мощный, но US-hosted — хуже для GDPR | +| **Amplitude** | Бесплатно tier | Хорош для cohorts, но US-hosted | + +**Рекомендация Stage 1**: PostHog Cloud EU (бесплатный tier) → при росте мигрировать на self-hosted. + +--- + +## Архитектура: как не нарушить GDPR + +### Разделение данных + +``` +user_id (UUID) ← идентификатор, хранится в основной БД + ↕ НЕТ связи +analytics_session_id ← анонимный токен для аналитики +``` + +События аналитики отправляются с `analytics_session_id`, не с `user_id`. +Демография (пол, возраст) — агрегируется при сборе, строки на пользователя не хранятся. + +### Что НЕ логировать никогда + +- Текст сообщений из сессий +- Ответы на вопросы анкеты (только шаг завершён / нет) +- IP-адрес в полном виде (только /24 префикс для гео) +- Точный timestamp + user_id вместе (профилирование) + +--- + +## Воронка (что мерить в первую очередь) + +``` +Install + └─ Open app ← install → open rate + └─ Complete questionnaire ← questionnaire completion + └─ Complete session 1 ← session 1 completion (ключевой показатель) + └─ Register ← registration rate + └─ Subscribe ← conversion rate + └─ D7 active ← early retention + └─ D30 active ← retention +``` + +Главный ранний индикатор здоровья продукта: **Session 1 completion rate**. +Если меньше 50% — проблема в онбординге. + +--- + +## Открытые вопросы + +- [ ] PostHog self-hosted vs Cloud EU — решить до Stage 1 launch +- [ ] Как считать DAU без user_id (anonymous session token lifecycle?) +- [ ] A/B тесты онбординга — нужны feature flags (PostHog умеет) diff --git a/personal/projects/psychologist-app/onboarding-ux.md b/personal/projects/psychologist-app/onboarding-ux.md index 9db83eed..66ded37c 100644 --- a/personal/projects/psychologist-app/onboarding-ux.md +++ b/personal/projects/psychologist-app/onboarding-ux.md @@ -482,3 +482,83 @@ Trial: **14 дней** (конверсия 42.5% vs 25.5% у 3-дневного) --- *Документ создан автоматически исследовательским агентом. Обновить при запуске A/B тестов.* +## Анкета первой сессии как сбор профиля + +### Проблема "слива на сборе данных" + +Традиционный онбординг: форма с полями "возраст / пол / что беспокоит" → 60%+ дропают. +Причина: это **ощущается как анкета**, а не как помощь. + +**Решение**: первая сессия *и есть* сбор профиля — замаскированный под диалог. +Пользователь отвечает на вопросы персонажа, не заполняет форму. +На выходе — заполненный `profile.md`, а не брошенная анкета. + +### Структура первой сессии (= сбор профиля) + +**Блок 1 — "Психотип" (анкета)** + +Короткий опросник 6-8 вопросов в начале — до диалога с агентом. +Люди *любят* психологические анкеты — не избегать их, использовать. + +Вопросы-карточки (быстрый выбор): +- Что тебя сюда привело? (тревога / выгорание / отношения / саморазвитие / просто интересно) +- Как ты обычно справляешься с трудным? (действую / думаю / обсуждаю / откладываю / не знаю) +- Когда ты последний раз по-настоящему отдыхал? (давно / недавно / не помню) +- Есть ли в твоей жизни кто-то, кому ты доверяешь полностью? (да / частично / нет) + +**Итог анкеты** — короткая "классификация" от персонажа: +> "Похоже, ты из тех, кто думает больше, чем говорит. Это интересно — и иногда непросто." + +Не диагноз. Не флатteri. Наблюдение, которое *узнаёт* себя. + +**Блок 2 — Диалог (агент ведёт к нужным данным)** + +Агент ведёт беседу так, чтобы органично собрать: +- Основная тема/запрос +- Паттерн поведения +- Желаемое состояние + +Это именно то, что нужно в `profile.md` — пользователь не знает что "проходит анкету". + +### Privacy messaging при онбординге + +**Где показывать**: сразу после анкеты, до первого диалогового экрана. +**Тон**: личный, от лица разработчика — не юридический язык. + +Пример экрана: + +``` +──────────────────────────────── + Прежде чем продолжить + + Это мой личный проект — не + корпорация, не стартап с + инвесторами. Я не торгую + твоими данными и никому + их не передаю. + + Всё что ты пишешь хранится + только у тебя. + + ○ Что я собираю для аналитики: + анонимные данные — возраст, + страна, как часто открываешь + приложение. Без имён, без + текстов сессий. + + Это помогает мне понять, + кому приложение реально + помогает. + + [ ] Не отправлять даже это + + [Понятно, продолжим →] +──────────────────────────────── +``` + +**Принципы**: +- Галочка "не отправлять ничего" — видимая, не спрятанная +- Pre-unchecked (пустая по умолчанию) если аналитика включена по умолчанию — не по GDPR, там нужен явный opt-in +- Pre-unchecked (пустая) у "не отправлять" — пользователь активно выбирает отключение +- Никакого юридического языка на этом экране — только человеческий + diff --git a/personal/projects/psychologist-app/overview.md b/personal/projects/psychologist-app/overview.md index 67aae4d7..da751736 100644 --- a/personal/projects/psychologist-app/overview.md +++ b/personal/projects/psychologist-app/overview.md @@ -242,6 +242,9 @@ Documents/UserProfile/ первая только iOS, Android через 2-3 месяца. ### Backend +- **Rate limiting**: per-user middleware на бэкенде (Redis sliding window) — защита от abuse. + Anthropic API key никогда не покидает сервер. Лимиты: RPM per user_id + daily token budget. + При превышении: throttle → 429, не hard ban сразу. - **Language model**: Claude Sonnet 4.6 (основа) + Opus 4.7 для глубоких сессий - Sonnet: $3/MTok in, $15/MTok out - Opus: $5/MTok in, $25/MTok out diff --git a/personal/projects/psychologist-app/session-design.md b/personal/projects/psychologist-app/session-design.md index 92e96ade..b028d55e 100644 --- a/personal/projects/psychologist-app/session-design.md +++ b/personal/projects/psychologist-app/session-design.md @@ -162,7 +162,42 @@ UI алгоритм (не агент!) --- -## 5. Открытые вопросы +## 5. State Persistence & Session Recovery + +### Сохранение стейта на каждом шаге + +Каждый шаг сессии сохраняется немедленно — не в конце: + +``` +step_state { + session_id: "2026-05-19", + user_id: "...", + phase: "dialogue", // intro | questionnaire | dialogue | insight | closing + current_question_idx: 2, + answered: [ {q: "...", a: "..."}, ... ], + last_activity_ts: 1747612800 +} +``` + +При следующем открытии приложения — автоматически восстанавливается точка, где пользователь остановился. Не начинает с начала. + +### Заброшенная сессия (пользователь пропал посередине) + +**Триггер**: last_activity_ts > 20 часов, сессия не завершена. + +**Действие (backend cron)**: +1. Принудительно **завершить сессию** — агент пишет partial summary на основе того, что успело ответить +2. Обновить `profile.md` — даже неполные данные полезны +3. Пометить сессию как `completed_partial` + +**Уведомление**: на следующий день **примерно в то же время** (± 30 мин от last_activity_ts предыдущих сессий) — push: +> "Мы не успели закончить в прошлый раз. Вернёмся?" + +**Retention protocol** (Stage 2): при N пропущенных сессиях подряд — запускается отдельный флоу "возвращение пользователя" с мягким реактивационным сообщением. Детали — в будущем документе. + +--- + +## 6. Открытые вопросы - [ ] Как именно Narrator детектирует что вопросы в 3-м лице и нужно переформулировать? Prompt rule или регекс-паттерн? - [ ] Сценарий планировщика — отдельный агент или встроен в посредника?