Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
43576a5
feat(landing): implement Problems meme-slider block with responsive s…
evn88 Jul 27, 2026
5d31eef
feat(landing): refine Problems section overlap and restore custom font
evn88 Jul 27, 2026
dce159f
feat: add responsive landing story section
evn88 Jul 28, 2026
0060b6d
fix: refine landing section overlaps
evn88 Jul 28, 2026
ef1c347
feat: add self-care landing section
evn88 Jul 28, 2026
9147961
fix: refine landing story transitions
evn88 Jul 28, 2026
48885b5
fix: tune landing section spacing
evn88 Jul 28, 2026
5b7c49b
feat: add responsive what helps section
evn88 Jul 28, 2026
6adbd05
feat(landing): add responsive free guide section
evn88 Jul 28, 2026
ee2f163
feat(landing): add responsive about section
evn88 Jul 28, 2026
d7139b8
feat: add services section to landing page
evn88 Jul 28, 2026
a5e224c
fix: refine landing paper transitions
evn88 Jul 28, 2026
b3433e9
feat(landing): add responsive faq section
evn88 Jul 28, 2026
f54b6ad
feat(landing): add ADHD story-line SVG and Intellij MCP integration
evn88 Jul 28, 2026
4f4eecc
chore: keep MCP config local
evn88 Jul 29, 2026
63e7870
fix(landing): localize sections and optimize animations
evn88 Jul 29, 2026
8a4fac4
feat(landing): локализован переключатель темы
evn88 Jul 29, 2026
9597c4a
perf: optimize landing images
evn88 Jul 29, 2026
dda6893
feat: add quick booking from landing page
evn88 Jul 29, 2026
af7215f
fix: освобождать слоты и унифицировать уведомления
evn88 Jul 29, 2026
f1ae331
fix: adjust dashboard content layout
evn88 Jul 29, 2026
25ece9a
fix: shorten calendar weekday labels
evn88 Jul 29, 2026
935fcf4
feat: redesign user sessions calendar
evn88 Jul 29, 2026
58538c5
feat: redesign today free slot selection
evn88 Jul 29, 2026
4ad9273
feat: improve quick booking modal
evn88 Jul 30, 2026
884dd92
feat: add booking contact options
evn88 Jul 30, 2026
b7cf3e0
fix(landing): polish layout and FAQ transition
evn88 Jul 30, 2026
14e0c73
fix(landing): unify torn paper transitions
evn88 Jul 30, 2026
3f77259
refine landing service cards
evn88 Jul 30, 2026
24f8011
polish landing typography and contact footer
evn88 Jul 30, 2026
2217165
feat(admin): добавлен API для получения групп клиентов и настроена по…
evn88 Jul 30, 2026
a7570bc
feat(telegram): добавить интеграцию Telegram-бота для рассылок, уведо…
evn88 Jul 30, 2026
81f004c
feat(telegram): добавить возможность генерации ссылки привязки Telegr…
evn88 Jul 30, 2026
9a2b7b2
feat(telegram): добавить возможность просмотра записей и бронирования…
evn88 Jul 30, 2026
8bd1eda
fix(telegram): очистка домена вебхука от дублирования путей и поддерж…
evn88 Jul 30, 2026
d02d1e9
security(telegram): добавить валидацию секретного токена secret_token…
evn88 Jul 30, 2026
8565e04
feat(telegram): добавить поле Vercel Protection Bypass Token для тест…
evn88 Jul 30, 2026
17c6ec9
style(telegram): рефакторинг модального окна настроек с фиксированной…
evn88 Jul 30, 2026
c647b0e
chore: [deploy] trigger preview build for telegram integration
evn88 Jul 30, 2026
ed4da7a
feat(dashboard): перенос настроек во вкладки профиля и редизайн карто…
evn88 Jul 30, 2026
f4f9101
feat(notifications): add dual-channel Telegram and Email delivery sys…
evn88 Jul 31, 2026
8381015
fix(telegram): optimize callback query booking handler with instant f…
evn88 Jul 31, 2026
21b8379
fix(telegram): [deploy] preserve original user role when booking slot…
evn88 Jul 31, 2026
d4206f0
feat(telegram): add optional raw webhook payload logging to system jo…
evn88 Jul 31, 2026
98eb4ed
feat(telegram): switch webhook logging from env to db settings with S…
evn88 Jul 31, 2026
3ca16f1
feat(admin): add toggle for Telegram webhook logging in system log se…
evn88 Jul 31, 2026
dae1c2e
feat(notifications): [deploy] добавлена поддержка фолбэка при отправк…
evn88 Jul 31, 2026
4e52578
feat(telegram): [deploy] добавить умное автообновление журнала и расш…
evn88 Jul 31, 2026
8640667
feat(telegram): [deploy] двухстороннее безусловное логирование входящ…
evn88 Jul 31, 2026
dafb111
feat(logs): [deploy] стрелочки направления запросов, контраст бейджей…
evn88 Jul 31, 2026
0fdf2ec
feat(logs): [deploy] выравнивание размера и стиля всех кнопок на стра…
evn88 Jul 31, 2026
92e8cdc
feat(logs): [deploy] заменить текстовые эмодзи на строгие SVG-иконки …
evn88 Jul 31, 2026
6dbf50d
feat(telegram): [deploy] автоподстановка активного Vercel bypass токе…
evn88 Jul 31, 2026
4d43c7b
feat(logs): [deploy] полноценное логирование response body для всех H…
evn88 Jul 31, 2026
a5283f2
fix(telegram): [deploy] явное разрешение callback_query в allowed_upd…
evn88 Jul 31, 2026
6cba0bc
feat(logs): [deploy] добавить выгрузку логов в файлах JSON, JSONL и C…
evn88 Jul 31, 2026
0830c13
feat(telegram): [deploy] добавлена команда запроса баланса пользовате…
evn88 Jul 31, 2026
dedc86d
refactor: modularize telegram workflows
evn88 Aug 1, 2026
2dbb768
refactor: decompose admin scheduling mutations
evn88 Aug 1, 2026
80ca384
feat(blog): обновить дизайн публичного блога
evn88 Aug 1, 2026
50422f0
fix(blog): [deploy] выровнять контейнеры страниц
evn88 Aug 1, 2026
f2ca342
refactor: remove Pillo from portal
evn88 Aug 2, 2026
dc21b94
refactor: reorganize dashboard settings navigation
evn88 Aug 2, 2026
8a5328e
[deploy] Добавить защищённое админ-меню Telegram
evn88 Aug 2, 2026
e349689
Refine landing hero and problems section
Aniamanson Aug 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
.env*
!.env.example

# vercel
.vercel
Expand All @@ -50,6 +51,15 @@ skills-lock.json
/app/.well-known/workflow/
/.claude/
/.codex/
.mcp.json
/.chrome-debug-profile/
/.codex-tmp-bin/
/.impeccable/
/.swc/
AGENTS.md
/docs/product-growth-roadmap.md

# local editor and merge backups
*.orig
*.rej
*.bak
8 changes: 0 additions & 8 deletions .mcp.json

This file was deleted.

34 changes: 34 additions & 0 deletions docs/architecture-review.ru.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Архитектурный аудит кодовой базы

## Выполненный этап

- Telegram-монолит уменьшен с 1005 строк до facade из 38 строк; сценарии разнесены по transport, application и domain
границам.
- Удалены production `any` из Telegram runtime, добавлены Zod contracts и типизированный callback protocol.
- Выделен общий `src/lib/base-url.ts`, чтобы модуль уведомлений не зависел от 1400-строчного email service ради одной
функции.
- Добавлены application services для подтверждения записи и активации пользователя с внутренней авторизацией и
идемпотентностью.
- Регистрация теперь создаёт Telegram-уведомление администратора с кнопкой `Сделать клиентом`.
- Новая бронь через бота содержит кнопку `Подтвердить запись`.

## Приоритеты дальнейшей декомпозиции

| Приоритет | Файл | Проблема | Целевая граница |
| --- | --- | --- | --- |
| P0 | `src/app/api/admin/events/[id]/route.ts` | route совмещает validation, billing, scheduling, email и Google sync | тонкий HTTP adapter + scheduling commands |
| P0 | `src/lib/email.ts` | 1400+ строк и несколько каналов/сценариев | email adapter + notification use cases + template data mappers |
| P1 | `src/modules/payments/financial/financial-service.server.ts` | ledger, pricing, charging, refunds и email outbox в одном сервисе | отдельные financial commands и repositories без изменения ledger-инвариантов |
| P1 | `src/app/api/actions/dashboard-actions.ts` | admin/client DTO и queries в одном action-файле | dashboard query services по scope |
| P1 | `src/app/[locale]/(admin)/admin/schedule/_components/event-dialog.tsx` | форма, billing UI и мутации в одном компоненте | RHF form sections + controller hook + explicit create/edit variants |
| P2 | `src/components/profile-form.tsx` | профиль, auth preferences и integrations смешаны | независимые settings sections с локальным состоянием |
| P2 | `src/modules/payments/paypal/service.ts` | provider API, mapping и бизнес-операции смешаны | PayPal adapter + payment application service |

## Правило для новых функций

Новый сценарий начинается с application command/query и минимального DTO. Route Handler, Server Action, workflow и
Telegram handler являются adapters и не дублируют бизнес-мутацию. Доступ проверяется на внешней границе и повторно в
server-only application service. Внешние эффекты запускаются после успешной транзакции и по возможности через outbox.

Большой файл не делится по формальному количеству строк: границей служит причина изменения. Transport, validation,
domain policy, persistence и presentation должны меняться независимо и иметь отдельные тесты.
15 changes: 0 additions & 15 deletions docs/codebase-guidelines.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@

Примеры из проекта:

- `src/app/[locale]/(dashboard)/app/pillo/page.tsx`
- `src/app/[locale]/(dashboard)/app/pillo/_components/pillo-app-shell.tsx`
- `src/app/[locale]/(dashboard)/app/pillo/_hooks/use-pillo-tabs.ts`
- `src/app/[locale]/(dashboard)/my/data/_actions/documents.actions.ts`
- `src/app/[locale]/(admin)/admin/blog/[id]/_components/blog-editor-form.types.ts`

Expand All @@ -94,7 +91,6 @@

- `profile-form.tsx`
- `theme-provider.tsx`
- `pillo-app-shell.tsx`
- `admin-payments-table.tsx`
- `take-confirmation.tsx`

Expand Down Expand Up @@ -144,7 +140,6 @@
- `use-heartbeat.ts`
- `use-push-notifications.ts`
- `use-user-events.ts`
- `use-pillo-tabs.ts`
- `use-blog-editor-lock.ts`

Правило:
Expand Down Expand Up @@ -273,7 +268,6 @@ CSS-файлы тоже придерживаются нижнего регист

Примеры:

- `src/app/[locale]/(dashboard)/app/pillo/_components/*`
- `src/app/[locale]/(dashboard)/my/sessions/_components/*`
- `src/app/[locale]/(admin)/admin/schedule/_components/*`
- `src/app/[locale]/(public)/blog/_components/*`
Expand All @@ -300,8 +294,6 @@ CSS-файлы тоже придерживаются нижнего регист

Примеры:

- `src/app/[locale]/(dashboard)/app/pillo/_hooks/use-pillo-tabs.ts`
- `src/app/[locale]/(dashboard)/app/pillo/_hooks/use-pillo-settings-form.ts`

Туда кладём hooks, если они:

Expand Down Expand Up @@ -393,7 +385,6 @@ CSS-файлы тоже придерживаются нижнего регист

Пример:

- `src/app/[locale]/(dashboard)/app/pillo/_hooks/use-pillo-medication-form.ts`

### 6.4 Чего не делать

Expand All @@ -417,7 +408,6 @@ CSS-файлы тоже придерживаются нижнего регист
- `modules/ai`
- `modules/backup`
- `modules/payments`
- `modules/pillo`
- `modules/system-logs`

Сюда кладём:
Expand All @@ -433,7 +423,6 @@ CSS-файлы тоже придерживаются нижнего регист
Примеры:

- `src/modules/backup/service.ts`
- `src/modules/pillo/schedule.ts`
- `src/modules/payments/factory.ts`
- `src/modules/system-logs/system-log-service.server.ts`

Expand All @@ -456,7 +445,6 @@ CSS-файлы тоже придерживаются нижнего регист
Сравнение:

- `src/lib/safe-url.ts` — общий helper;
- `src/modules/pillo/schedule.ts` — доменная логика расписания;
- `src/lib/prisma.ts` — инфраструктурный доступ к Prisma;
- `src/modules/backup/workflow.ts` — доменная orchestration-логика backup.

Expand Down Expand Up @@ -529,7 +517,6 @@ CSS-файлы тоже придерживаются нижнего регист

- `blog-editor-form.types.ts`
- `src/app/[locale]/(admin)/admin/users/_components/types.ts`
- `src/app/[locale]/(dashboard)/app/pillo/_components/types.ts`

### 9.2 Общие типы

Expand Down Expand Up @@ -626,7 +613,6 @@ email-вёрстки структуру или табличную расклад
- `create-site-backup-workflow.ts`
- `restore-site-backup-workflow.ts`
- `session-reminder-workflow.ts`
- `pillo-intake-reminder-workflow.ts`

Если модуль домена лишь вызывает workflow, адаптер можно держать в домене или `lib`, но точка входа workflow должна оставаться в `src/workflows`.

Expand Down Expand Up @@ -724,7 +710,6 @@ email-вёрстки структуру или табличную расклад
Хорошо:

- `use-mobile.tsx`
- `use-pillo-tabs.ts`

### Утилиты

Expand Down
6 changes: 5 additions & 1 deletion docs/in-app-notifications.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,14 @@ await resolveUserNotificationByKey(userId, systemNotificationKeys.incompleteInta

После первой регистрации также создаётся одноразовое приветственное уведомление:

- `otpRegistration`: регистрация по одноразовому коду, содержит переход к заполнению имени;
- `otpRegistration`: регистрация по одноразовому коду;
- `googleRegistration`: регистрация через Google;
- если имя уже сохранено, приветствие обращается к пользователю по имени и не показывает лишнее действие;
- если имени нет, приветствие предлагает заполнить его и содержит переход в профиль;
- оба сценария сообщают, что полный функционал станет доступен после подтверждения учётной записи администратором.
- каждый активный администратор получает дедуплицированное уведомление о новом аккаунте со ссылкой на управление пользователями.
- после перевода нового аккаунта из `GUEST` в `USER` все активные уведомления администраторов об этой регистрации
автоматически отмечаются прочитанными, а пользователь получает дедуплицированное уведомление об активации.

## История уведомлений

Expand Down
4 changes: 2 additions & 2 deletions docs/schedule-timezone-guidelines.ru.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Правила работы с датами и часовыми поясами расписания

Этот документ обязателен для разработчиков и AI-агентов, которые изменяют расписание, консультации, личный кабинет,
админский календарь, email-уведомления или Pillo.
админский календарь или email-уведомления.

## Единая точка истины

Expand Down Expand Up @@ -68,7 +68,7 @@ const dateTime = useScheduleDateTime(timeZone, locale);

## Date-only поля

Поля, которые являются бизнес-датой без времени (например, дата окончания курса Pillo), нельзя трактовать как момент
Поля, которые являются бизнес-датой без времени (например, дата окончания действия документа), нельзя трактовать как момент
события и бездумно конвертировать в timezone. Нужно сохранить их доменную семантику и использовать явно выбранный
стабильный timezone/формат через shared-сервис.

Expand Down
92 changes: 92 additions & 0 deletions docs/telegram-bot-architecture.ru.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Архитектура Telegram-бота

## Цель

Telegram является внешним transport-слоем. Он принимает update, определяет пользовательское действие и вызывает
server-only application service. Бизнес-правила ролей, расписания, платежей и уведомлений не должны жить в webhook
route или Telegram API client.

## Структура модуля

```text
src/modules/telegram/
├── telegram-service.server.ts # совместимый публичный facade
├── telegram-types.ts # валидируемые transport contracts
├── telegram-config.server.ts # конфигурация и webhook secret
├── telegram-api-client.server.ts # единственный adapter Telegram Bot API
├── telegram-account.server.ts # привязка аккаунта и настройки канала
├── telegram-broadcast.server.ts # административные рассылки
├── telegram-admin-notifications.server.ts
├── telegram-formatter.ts # безопасное форматирование HTML-сообщений
└── bot/
├── callback-data.ts # публичный callback protocol
├── keyboards.ts # reply/inline keyboards
├── webhook-router.server.ts # registry команд и callbacks
└── handlers/ # один пользовательский сценарий на handler
```

Бизнес-мутации вынесены за пределы transport-модуля:

- `src/modules/scheduling/booking-approval.server.ts` — атомарное подтверждение обычной заявки, списание оплаты и
запуск post-commit уведомлений;
- `src/modules/users/user-approval.server.ts` — идемпотентный переход `GUEST → USER` и завершение уведомлений
администраторов.

## Поток webhook

1. `POST /api/telegram/webhook` проверяет, что бот включён.
2. Заголовок `x-telegram-bot-api-secret-token` сравнивается через `crypto.timingSafeEqual` до чтения и логирования body.
3. Update валидируется Zod-схемой как `unknown`.
4. Router находит command/callback handler в registry.
5. Handler получает минимальный DTO, проверяет доступ и вызывает application service.
6. Application service повторно проверяет роль инициатора и выполняет условную/транзакционную мутацию.

## Административные callbacks

Кнопки изменения данных работают только при одновременном выполнении условий:

- `adminChatId` настроен как личный Telegram ID администратора;
- этот Telegram ID привязан к пользователю сайта;
- пользователь имеет роль `ADMIN` и не отключён;
- callback относится к разрешённой операции из typed protocol.

Подтверждение записи использует условный переход `PENDING_CONFIRMATION → SCHEDULED`. Повторное нажатие не выполняет
повторное списание. Активация пользователя допускает только переход `GUEST → USER`; через callback нельзя назначить
роль `ADMIN`, активировать отключённый аккаунт или изменить уже существующего администратора.

## Добавление новой команды

1. Добавить handler в `bot/handlers/<action>-command.server.ts`.
2. Handler должен принимать transport DTO, получать только необходимые поля и проверять статус аккаунта.
3. Зарегистрировать matcher в `commandHandlers` файла `webhook-router.server.ts`.
4. Бизнес-мутацию разместить в соответствующем domain/application модуле, а не в handler.
5. Добавить unit-тест matcher/handler и тест application service.

## Добавление новой callback-кнопки

1. Добавить вариант discriminated union, builder и parser в `bot/callback-data.ts`.
2. Учитывать ограничение Telegram: `callback_data` не длиннее 64 байт.
3. Добавить keyboard factory в `bot/keyboards.ts`.
4. Создать отдельный handler и зарегистрировать его в `callbackHandlers`.
5. Для административной мутации повторно проверить Telegram ID, роль `ADMIN` и domain-инварианты.
6. Сделать мутацию идемпотентной через условный `updateMany`, unique key или operation key.

## Эксплуатационные требования

- `AUTH_SECRET` обязателен. Fallback-секретов нет.
- Подробные payload-логи webhook записываются только при `telegramWebhookLogsEnabled`.
- Токен бота и webhook secret нельзя помещать в diagnostic payload.
- Весь динамический текст для HTML parse mode проходит через `escapeTelegramHtml()`.
- Для дат расписания используется только `createScheduleDateTime()`.
- Production consumers постепенно переводятся с facade на прямой узкий server-only import; facade сохраняется для
обратной совместимости.

## Следующий этап

1. Перевести web-confirmation из `api/admin/events/[id]` на тот же scheduling application service и расширить его для
reschedule-заявок. Сейчас Telegram намеренно подтверждает только обычную новую заявку.
2. Разделить `src/lib/email.ts` на channel adapters и notification use cases. `getBaseUrl()` уже вынесен в независимый
`src/lib/base-url.ts`, а Telegram API imports больше не проходят через общий facade.
3. Добавить persistent outbox для внешних Telegram/Email/Google post-commit эффектов, чтобы временный сбой канала можно
было повторить без повторения бизнес-мутации.
4. Добавить audit event с actor ID для всех административных Telegram-команд.
Loading
Loading