[2026-05-19] psychologist-app: анкета онбординга, state persistence, analytics.md, rate limiting, сброс данных
This commit is contained in:
@@ -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 умеет)
|
||||
@@ -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 (пустая) у "не отправлять" — пользователь активно выбирает отключение
|
||||
- Никакого юридического языка на этом экране — только человеческий
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 или регекс-паттерн?
|
||||
- [ ] Сценарий планировщика — отдельный агент или встроен в посредника?
|
||||
|
||||
Reference in New Issue
Block a user