[2026-09-29] eagle: personal/index.md personal/plans/zulip-decommission.md personal/projects/zulip-router.md personal/tech/docker-mac-disk-issues.md personal/tech/zulip-message-history.md
This commit is contained in:
1 parent
e75cf79e79
commit
62f19eeecb
5 files changed
+342
No files matched your search
@@ -104,6 +104,8 @@ colima ssh -- df -h /dev/vdb1
|
||||
- [[projects/balda/setup]] — Balda агенты (Валера, Клавдий)
|
||||
- [[how-to/hermes-eagle-mac]] — Hermes на Mac, Zulip Docker стек (RabbitMQ pitfall про Khepri)
|
||||
- [[how-to/openmediavault-rpi5]] — build cache на RPi (та же проблема ENOSPC)
|
||||
- [[plans/zulip-decommission]] — план сноса Zulip с сохранением истории
|
||||
- [[tech/zulip-message-history]] — история переписки в SQLite (для поиска)
|
||||
|
||||
## ✅ Чистка 2026-09-29 — освобождено 41 ГБ
|
||||
|
||||
@@ -208,6 +210,10 @@ docker ps --format '{{.Names}} {{.Image}}' | grep -i balda # → пусто
|
||||
⚠️ **На Kraken ничего не снесено** — там `balda-executor-mcp` работает,
|
||||
текущий рабочий образ `balda-mm:0.1.15-pr8-480ec821-runtime210`.
|
||||
|
||||
> 📌 **2026-09-29 (позже в тот же день):** история Zulip выгружена в SQLite и
|
||||
> Zulip готовится к сносу — см. [[tech/zulip-message-history]] и
|
||||
> [[plans/zulip-decommission]]. Контейнеры `zulip-*` из списка ниже — кандидаты на удаление.
|
||||
|
||||
|
||||
### Живые контейнеры (16, все рабочие)
|
||||
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
# Zulip Message History — SQLite (поиск истории переписки)
|
||||
|
||||
_Создано: 2026-09-29_
|
||||
|
||||
## Что это
|
||||
|
||||
Вся история переписки Zulip (134 734 сообщения, 197 тредов, 11 стримов) выгружена в
|
||||
**один SQLite-файл**. Zulip как транспорт выводится из эксплуатации — история остаётся
|
||||
в этом файле.
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| **Файл** | `~/Documents/zulip_message_history.sqlite` |
|
||||
| Размер | 78.1 MB |
|
||||
| Сообщений | **134 734** (134 688 в стримах + 46 личек) |
|
||||
| Стримов | 11 |
|
||||
| Тредов (`topics`) | 197 |
|
||||
| Источник | `zulip-database-1` (Postgres 14, `~/Developer/zulip/docker-compose.yml`) |
|
||||
| Снимок на | 2026-09-29 |
|
||||
| Бэкап | `~/backup/zulip-final/` (см. §Бэкапы) |
|
||||
|
||||
## Схема
|
||||
|
||||
```sql
|
||||
streams (id, name) -- 11 каналов
|
||||
topics (id, stream_id → streams.id, name) -- 197 тредов
|
||||
messages (id, topic_id → topics.id, kind, sender,
|
||||
sender_email, date_sent, content) -- 134 734
|
||||
messages_fts (fts5: content, content='messages') -- полнотекстовый поиск
|
||||
```
|
||||
|
||||
- `kind` = `stream` | `dm`
|
||||
- `content` — **markdown-исходник** Zulip (не HTML-рендер); HTML был в `rendered_content`
|
||||
и в дамп не попал осознанно
|
||||
- `date_sent` — ISO-8601 UTC (`2026-09-29 06:29:41.829084+00`)
|
||||
|
||||
### Индексы
|
||||
|
||||
| Индекс | Назначение |
|
||||
|---|---|
|
||||
| `messages_fts` (FTS5) | поиск по тексту через `MATCH` |
|
||||
| `idx_messages_topic` | сообщения одного треда |
|
||||
| `idx_messages_date` | диапазон по датам |
|
||||
| `idx_topics_stream` | треды одного стрима |
|
||||
|
||||
## Как искать историю (главное)
|
||||
|
||||
```bash
|
||||
DB=~/Documents/zulip_message_history.sqlite
|
||||
```
|
||||
|
||||
### 1. Поиск по тексту
|
||||
|
||||
```bash
|
||||
sqlite3 "$DB" "
|
||||
SELECT s.name AS stream, t.name AS topic, m.sender, m.date_sent,
|
||||
substr(m.content, 1, 3000) AS content
|
||||
FROM messages_fts f
|
||||
JOIN messages m ON m.id = f.rowid
|
||||
JOIN topics t ON t.id = m.topic_id
|
||||
JOIN streams s ON s.id = t.stream_id
|
||||
WHERE messages_fts MATCH 'docker jellyfin'
|
||||
ORDER BY m.date_sent DESC LIMIT 30;"
|
||||
```
|
||||
|
||||
### 2. Список тредов с количеством сообщений
|
||||
|
||||
```bash
|
||||
sqlite3 -column -header "$DB" "
|
||||
SELECT s.name AS stream, t.name AS topic, count(*) AS msgs
|
||||
FROM messages m
|
||||
JOIN topics t ON t.id = m.topic_id
|
||||
JOIN streams s ON s.id = t.stream_id
|
||||
GROUP BY t.id ORDER BY msgs DESC;"
|
||||
```
|
||||
|
||||
### 3. Прочитать тред целиком
|
||||
|
||||
```bash
|
||||
sqlite3 "$DB" "
|
||||
SELECT m.date_sent || ' | ' || m.sender || char(10) || m.content || char(10) || '==='
|
||||
FROM messages m
|
||||
WHERE m.topic_id = (SELECT id FROM topics WHERE name = 'Home assistant setup' LIMIT 1)
|
||||
ORDER BY m.date_sent;"
|
||||
```
|
||||
|
||||
### 4. Найти сообщения конкретного человека по ключевым словам
|
||||
|
||||
```bash
|
||||
sqlite3 "$DB" "
|
||||
SELECT t.name, m.date_sent, substr(m.content,1,500)
|
||||
FROM messages m JOIN topics t ON t.id = m.topic_id
|
||||
WHERE m.sender = 'Alex' AND m.content LIKE '%план%'
|
||||
ORDER BY m.date_sent DESC LIMIT 20;"
|
||||
```
|
||||
|
||||
### ⚠️ FTS5-синтаксис
|
||||
|
||||
Токенизатор — `unicode61` (дефолт): поиск по **целым словам**, стемминга нет.
|
||||
|
||||
| Хочу | Запрос |
|
||||
|---|---|
|
||||
| слово `docker` | `MATCH 'docker'` |
|
||||
| префикс `dock…` | `MATCH 'dock*'` |
|
||||
| фраза | `MATCH '"zulip router"'` |
|
||||
| AND | `MATCH 'docker jellyfin'` |
|
||||
| OR | `MATCH 'docker OR jellyfin'` |
|
||||
| НЕ | `MATCH 'docker NOT podman'` |
|
||||
|
||||
`собрал` **не** найдёт `собрать` — стемминга нет. Для поиска по подстроке внутри слова
|
||||
нужен `trigram`-токенизатор (не включён; пересборка FTS-таблицы).
|
||||
|
||||
## Стримы и треды (снимок)
|
||||
|
||||
| Стрим | Сообщений | Тредов |
|
||||
|---|---|---|
|
||||
| personal | 111 534 | 95 |
|
||||
| master | 7 630 | 29 |
|
||||
| projects | 7 524 | 20 |
|
||||
| executor | 7 355 | 32 |
|
||||
| Zulip | 432 | 1 |
|
||||
| daily-brief | 182 | 12 |
|
||||
| general | 15 | 1 |
|
||||
| inbox | 14 | 3 |
|
||||
| journal | 1 | 1 |
|
||||
| focus | 1 | 1 |
|
||||
| Direct messages | 46 | 2 |
|
||||
|
||||
Крупнейшие треды (personal): `Home assistant setup` 12 196 · `truenas jellyfin` 12 059 ·
|
||||
`Балда/валера` 9 454 · `ZONT Config compiler` 6 585 · `✔ media toolbox setup` 6 198.
|
||||
|
||||
## 🔴 Ограничение — база не живая
|
||||
|
||||
Файл — **снимок на 2026-09-29**. После сноса Zulip новые сообщения сюда не попадают.
|
||||
Живой поиск свежей переписки — только в Mattermost (`hermes-maintenance`,
|
||||
`a6nyh77eyjbn5c1owh1i8eebee`). Разделять явно: «историческое (до 29.09)» → SQLite;
|
||||
«что обсуждали вчера» → Mattermost.
|
||||
|
||||
## Как это было сделано (воспроизводимо)
|
||||
|
||||
1. **Экспорт из Postgres в CSV.** Ключ — `\copy` (не `COPY`), потому что `COPY` через
|
||||
`docker exec` требует прав на файл внутри контейнера, а `\copy` пишет в stdout.
|
||||
Колонки: `id, kind, stream, topic, dm_user_id, sender, sender_email, date_sent, content`.
|
||||
|
||||
```bash
|
||||
docker exec zulip-database-1 psql -U zulip -d zulip -c "\copy (
|
||||
SELECT m.id, 'stream' AS kind, s.name AS stream, m.subject AS topic, 0 AS dm_user_id,
|
||||
u.full_name AS sender, u.email AS sender_email, m.date_sent, m.content
|
||||
FROM zerver_message m
|
||||
JOIN zerver_recipient r ON r.id = m.recipient_id
|
||||
JOIN zerver_stream s ON s.id = r.type_id
|
||||
JOIN zerver_userprofile u ON u.id = m.sender_id
|
||||
WHERE r.type = 2 ORDER BY m.id
|
||||
) TO STDOUT WITH (FORMAT csv, HEADER false)" > /tmp/zulip-export/messages.csv
|
||||
```
|
||||
|
||||
Личные сообщения (`r.type = 1`) — отдельным запросом в `dms.csv`, топик = `DM user #<id>`.
|
||||
В БД лички в `zerver_recipient.type_id = 1`, у них нет `subject` — отсюда синтетический топик.
|
||||
|
||||
2. **Сборка SQLite** — скрипт `build_sqlite.py` (Python stdlib `csv` + `sqlite3`), создаёт
|
||||
таблицы, наполняет `streams`/`topics`/`messages`, строит индексы и наполняет FTS5.
|
||||
|
||||
3. **Верификация** — `PRAGMA integrity_check`, `PRAGMA foreign_key_check`,
|
||||
`count(*)` против Postgres, FTS-запрос по реальному слову.
|
||||
|
||||
### 🔴 Питфоллы, которые стоили времени
|
||||
|
||||
- **TSV рвётся на многострочном контенте.** Первый заход был с `-A -F$'\t'` → вместо
|
||||
134 688 строк получилось **486 751** (переносы строк внутри сообщений режут TSV).
|
||||
Решение: `WITH (FORMAT csv)` — кавычки экранируют переносы корректно. `wc -l` на CSV
|
||||
всё равно покажет завышенное число переносов — это ожидаемо, **считать строки нужно
|
||||
парсером, а не `wc`**.
|
||||
- **`rendered_content` — это HTML.** Для читаемой истории нужен `content` (markdown).
|
||||
HTML-дамп бесполезен без рендера.
|
||||
- **`content` может содержать что угодно** — включая NUL и гигантские блоки кода.
|
||||
В `build_sqlite.py` нужен `csv.field_size_limit(50MB)`, иначе падает на больших сообщениях.
|
||||
- **CSV-колонок было 9, а проверял на 8** — первая сборка дала 0 сообщений и
|
||||
134 734 ошибки «bad field count». Читать позиционно по факту заголовка, не по памяти.
|
||||
|
||||
## Бэкапы
|
||||
|
||||
| Что | Где |
|
||||
|---|---|
|
||||
| SQLite (история) | `~/Documents/zulip_message_history.sqlite` |
|
||||
| CSV-дампы | `/tmp/zulip-export/messages.csv` (56 MB), `dms.csv` (18 KB) |
|
||||
| Compose + env Zulip | `~/Developer/zulip/docker-compose.yml`, `.env.zulip` |
|
||||
|
||||
## Что НЕ выгружалось (осознанно, по указанию Alex)
|
||||
|
||||
Только переписка + структура тредов. Вне выгрузки:
|
||||
|
||||
- вложения/аплоады (`volume zulip_zulip-data`, 38.1 MB — `uploads/`, `certs/`)
|
||||
- аватары, реакции, подписки, метаданные организаций
|
||||
- настройки стримов, права, история изменений сообщений
|
||||
|
||||
Если понадобится картинка из старого треда — её в SQLite нет, она была в volume.
|
||||
|
||||
## Снос Zulip — чек-лист
|
||||
|
||||
⚠️ **Пока не выполнено.** Файл сделан как страховка перед сносом.
|
||||
|
||||
```bash
|
||||
cd ~/Developer/zulip
|
||||
docker compose down
|
||||
docker volume rm zulip_zulip-data zulip_zulip-pgdata zulip_zulip-rabbitmq zulip_zulip-redis
|
||||
docker rmi zulip/docker-zulip:11.6-0 # ~3.84 GB
|
||||
```
|
||||
|
||||
Стек: `zulip-zulip-1` (`zulip/docker-zulip:11.6-0`, порты 8000/8443), `zulip-database-1`
|
||||
(`zulip/zulip-postgresql:14`), `zulip-rabbitmq-1`, `zulip-memcached-1`, `zulip-redis-1`.
|
||||
Объём volumes ≈ 1.1 GB (pgdata 503 MB на диске, БД 439 MB; data 38 MB).
|
||||
|
||||
### ⚠️ Зависимости, которые сломаются
|
||||
|
||||
| Компонент | Что будет |
|
||||
|---|---|
|
||||
| `zulip-router` (Go, `~/Developer/zulip-router/`) | мёртвый — поллит Zulip Events API. Убрать из compose, иначе restart-loop |
|
||||
| `zulip-bot-routing` (Еagle/Кит/Валера/Клавдий webhook) | маршрутизация в Zulip перестанет работать |
|
||||
| Hermes `platforms: zulip` в `~/.hermes/config.yaml` | платформа отвалится; транспорт уже переехал на Mattermost |
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- [[projects/zulip-router]] — архитектура event-роутера (Go), конфиг ботов
|
||||
- [[tech/hermes-whale-mattermost-transport]] — текущий транспорт Hermes
|
||||
- [[how-to/hermes-eagle-mac]] — Hermes на Mac, Zulip Docker стек, RabbitMQ/Khepri pitfall
|
||||
- [[tech/docker-mac-disk-issues]] — почему Zulip тормозил (переполнение диска VM)
|
||||
- [[plans/zulip-decommission]] — план вывода Zulip из эксплуатации
|
||||
Reference in new issue
Block a user