- deploy/glchat-cli.sh: reset-password/make-admin/remove-admin больше не
заглушки «появится в фазе 1» (AGENT.md 10.7), добавлены totp-setup,
totp-reset и delete-user; подкоманды обслуживания идут через общий app_cli
- cmd/glchat: команда delete-user (мягкое удаление как в админ-панели,
защита от удаления инстанс-админа и подтверждение --yes), исправлен
потерянный комментарий cliCleanup
- deploy/install.sh: убраны устаревшие формулировки про фазу 1
- web: политика повторов запросов — 429 повторяется с паузой retry_after_ms
(до двух раз, не дольше 5 с), 4xx не повторяются; тесты web/tests/queryRetry.test.ts
- scripts/test-install.sh: проверка, что заглушек в CLI не осталось
Уведомления в браузере и на телефоне: сервер сам решает, кому их слать, и
подписывает запрос VAPID-ключом, поэтому уведомление приходит, даже когда
клиент закрыт.
Сервер:
- миграция 00021: `push_subscriptions` (эндпоинт уникален, ключи, счётчик
неудач, время последней доставки);
- `internal/push` — VAPID-ключи (приватный PKCS#8 из конфига, публичный
выводится из него), правила уведомлений повторяют
`web/src/lib/desktopNotifications.ts` (упоминания и личные беседы, без своих
и системных сообщений), очередь доставки, TTL 12 часов, Topic по комнате;
- 404/410 от push-сервиса удаляют подписку сразу, 5 неудач подряд — тоже,
иначе копились бы мёртвые эндпоинты; retention чистит «молчащие» подписки;
- `internal/httpx/safeurl.go` — общий запрет внутренних адресов с проверкой
адреса в момент подключения (DNS rebinding): эндпоинт подписки приходит от
клиента, и без проверки сервер сам себе организует SSRF;
- `internal/gateway/presence.go` — `IsUserOnline`: если получатель в клиенте,
уведомление покажет клиент, дублировать на телефон не нужно;
- ручки `GET /push/config`, `GET|POST|DELETE /push/subscriptions`, лимиты
10 подписок и 20 уведомлений в минуту; ключ p256dh проверяется как настоящая
точка P-256;
- установщик генерирует `VAPID_PRIVATE_KEY` (openssl, PKCS#8 DER в base64) и
`VAPID_SUBJECT`, ключ переиспользуется при переустановке; для ручной установки
есть `glchat vapid-keys`; `features.web_push_enabled` виден в `/meta`.
Тесты: правила и VAPID, доставка с поддельным push-эндпоинтом (шифрование,
заголовки VAPID/TTL/Topic, очистка мёртвых подписок), ручки и лимиты, отправка
при личном сообщении и упоминании, пропуск онлайн-получателей, миграция на
чистой БД.
`glchat update` на стенде с внешним прокси всегда сообщал «приложение не
поднялось»: readyz проверялся на 127.0.0.1, а приложение слушает адрес в
WireGuard (GLCHAT_APP_BIND). Тот же дефект был в restore.sh и в `glchat status`
(health показывался как unreachable). Добавлен общий помощник app_check_url.
Переключение профиля — повторная установка, и без флагов она переписала бы
compose на встроенный прокси. Теперь CLI восстанавливает домен, режим прокси,
адреса привязки, внешний TURN и ignore-ip из .env.
- cmd/loadgen: держит заданное число WS-клиентов Gateway, шлёт сообщения с
нужной частотой, измеряет задержку доставки (p50/p95/p99/max), ответы API,
разрывы соединений и пишет отчёт в JSON;
- glchat create-user (CLI + обёртка): создаёт аккаунты в обход выключенной
регистрации, пакетно (--count/--prefix), при --sessions сразу выдаёт сессии
и складывает учётные данные в файл 600 — иначе сотня клиентов не сможет
войти из-за лимита попыток по IP;
- auth: CreateUserByOperator и IssueSessionForOperator с тестом;
- web/e2e/voice-ten.spec.ts: десять участников в одной голосовой комнате,
проверка плиток, входящего аудио и слоя 1080p60 у клиента; сессии берутся
из файла (без формы входа);
- .gitignore: каталоги вывода Playwright test-results*.
- glchat verify-backup: расшифровка age, integrity_check, foreign_key_check,
схема и состав данных, сверка с манифестом; живые данные не трогает
- чистка удаляет файлы на диске, у которых не осталось записи в базе (так
оставались вложения удалённых серверов), и пустые подкаталоги; работает
через os.Root, чтобы символическая ссылка не вывела за каталог файлов
- удаление сервера теперь чистит и содержимое файлов, а не только записи
- install.sh пишет значения .env с пробелами в кавычках: файл подключается
через `set -a && . .env`, иначе имя главного сервера выполнялось как команда
- тесты: Go на уборку файлов без записи (свежие не трогаются, пустые
каталоги удаляются)
- internal/retention: истёкшие сессии, аудит старше RETENTION_AUDIT_DAYS и
файлы без ссылок старше RETENTION_ORPHAN_HOURS; сиротой файл считается
только если на него не ссылается ничего (вложения, аватары, оформление
сервера, комнат, ролей, эмодзи, звуки, вебхуки, приглашения)
- обслуживание запускается в приложении по RETENTION_INTERVAL_SECONDS;
команды glchat cleanup и glchat reindex делают то же вручную
- PWA: манифест с иконками и shortcuts, офлайн-страница, сервис-воркер
(кэш только /assets/*, приватные запросы не кэшируются)
- тесты: Go на чистку (сирота удаляется, используемые файлы и свежие сироты
остаются, истёкшая сессия уходит), Vitest на манифест и регистрацию воркера