OpenSpec: разнести openspec по проектам

This commit is contained in:
2026-09-11 17:33:02 +00:00
parent 6a4ccd3e6d
commit e17dd7f901
18 changed files with 1741 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-08
@@ -0,0 +1,65 @@
# Design — icq-fix-prosody-network
## Итоговая команда
```bash
cd /opt/icq && docker compose up -d --force-recreate prosody
```
Docker compose пересоздаст контейнер `icq-prosody` из того же образа
(`gitea.nixg.ru/hermes/icq-prosody:13.0`) с теми же volume'ами и подключит его
к сети `icq_default` (как указано в docker-compose.yml). После этого webchat
и slidgram снова видят prosody по имени `icq-prosody`.
Образ не меняется (config-hash из inspect = 6523667b1cb848380db7b2b77c15d3d1d0beeb303c8d03de2646699012672f85 —
тот же compose-проект icq). Данные на volume'ах `./data`, `./config`, `./certs`,
`./modules`, `./logs` — не затрагиваются.
## Порядок
1. **Снимок состояния ДО** (для сравнения):
- `docker ps --format '{{.Names}} {{.Networks}}'` — зафиксировать пустую сеть у prosody.
- `docker network inspect icq_default` — зафиксировать состав (webchat, slidgram).
2. **Пересоздание:**
- `cd /opt/icq && docker compose up -d --force-recreate prosody`
- дождаться `Started` и статуса `Up`.
3. **Проверка сети (изнутри compose):**
- `docker ps --format '{{.Names}} {{.Networks}}'` → prosody в icq_default.
- `docker network inspect icq_default` → prosody с IP.
- `docker exec icq-prosody hostname -i` → непустой IP.
- `docker exec icq-webchat getent hosts icq-prosody` → резолвится в 172.27.0.x.
4. **Проверка приложения:**
- `curl -i` к BOSH/WS через nginx/Caddy на 5280, проверить, что веб-клиент
получает ответ (VirtualHost nixg.ru + consider_websocket_secure=true уже в конфиге).
- `docker logs icq-prosody --tail 100` — нет новых ошибок, компонент
telegram.nixg.ru аутентифицирован.
- `docker logs icq-webchat --tail 50` — nginx отдаёт страницу без ошибок.
- `docker logs icq-slidgram --tail 50` — мост без ошибок аутентификации.
5. **Проверка снаружи:**
- `curl -i https://chat.nixg.ru/` через Caddy → 200.
- WS: `curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" ...` на
wss://xmpp.nixg.ru (или через браузер/логи) → HTTP 101.
## Откат
Если после пересоздания что-то пошло не так (маловероятно — конфиг/образ не менялись):
```bash
cd /opt/icq && docker compose up -d # повторное создание без force
# или, если совсем плохо:
docker start icq-prosody # старый контейнер ещё существует до пересоздания
```
Volume'ы не трогаем; данные не теряются. Резервная копия текущего состояния:
`docker inspect icq-prosody > /tmp/icq-prosody-inspect-before.json` (снимок до пересоздания).
## Затронутые файлы
Не меняем ни одного файла конфигурации. Только состояние Docker (контейнер).
## Затрагиваемые сервисы/порты
- prosody: 5222/5269/5280/5281 (все сохраняются из compose)
- webchat: 8081 (nginx, проксируется Caddy на vps02)
- slidgram: 5347 (external component)
- Сеть: icq_default (172.27.0.0/16, шлюз 172.27.0.1)
@@ -0,0 +1,58 @@
# Proposal — icq-fix-prosody-network
## Почему
С 2026-09-08 chat.nixg.ru (веб-клиент Converse.js) снова показывает бесконечную загрузку.
Ручной запуск контейнера prosody не помог.
**Корневая причина (подтверждена инспекцией):**
- Контейнер `icq-prosody` запущен вручную вне docker compose (`docker start`, пересоздан
вручную 2026-09-08T13:33) и **не подключён ни к одной Docker-сети**:
- `docker ps -a` → колонка Networks у `icq-prosody` пустая;
- `docker network inspect icq_default` → в сети только `icq-webchat` (172.27.0.2)
и `icq-slidgram` (172.27.0.4), prosody отсутствует;
- `docker inspect icq-prosody --format '{{json .NetworkSettings.Networks}}'` → `{}`;
- `docker exec icq-prosody hostname -i` → пусто (нет IP в контейнере).
- Из-за этого `icq-webchat` не может достучаться до Prosody по имени `icq-prosody`
(DNS icq_default не резолвится), WebSocket-соединение не устанавливается →
«бесконечная загрузка».
- `NetMode=icq_default` в метаданных — обманчиво: метка осталась, но фактического
подключения к сети нет (вероятно, контейнер пересоздан вне compose).
## Что делаем
Пересоздать `icq-prosody` штатно через docker compose (force-recreate), чтобы он
вернулся в сеть `icq_default` вместе с webchat и slidgram. Проверить, что:
- контейнер подключён к `icq_default` с IP;
- webchat и slidgram видят prosody по имени `icq-prosody`;
- chat.nixg.ru снова открывается (WS connect → 101);
- мост telegram.nixg.ru по-прежнему аутентифицирован;
- после рестарта ничего не сломалось (логотипы, S2S, http_upload).
## Объём
Один сервис (`prosody`), одна команда `docker compose up -d --force-recreate prosody`
(+ проверки). Без изменений конфигов и образов.
## Принятые решения
- Не менять конфиги Prosody, nginx, DNS — только вернуть контейнер в compose-жизненный цикл.
- Не трогать данные (./data, ./config, ./logs) — они на volume'ах.
- Верификацию делать и изнутри (docker exec), и снаружи (curl через Caddy/nginx).
## Риски и откат
- **Риск:** force-recreate может на пару секунд уронить веб-чат/федерацию. Приемлемо.
- **Откат:** `docker compose up -d` (пересоздание с теми же volume'ами) или
`docker start icq-prosody` если что-то пошло не так — данные не теряются (volume'ы).
- **Не трогаем** данные пользователей; никаких удалений.
## Критерии приёмки
- [ ] `docker ps` показывает `icq-prosody` в сети `icq_default` (не пустая колонка)
- [ ] `docker network inspect icq_default` содержит `icq-prosody` с IP
- [ ] `docker exec icq-prosody hostname -i` возвращает IP (не пусто)
- [ ] из webchat резолвится и коннектится `icq-prosody:5280`
- [ ] https://chat.nixg.ru грузится, Converse показывает окно входа (не бесконечная загрузка)
- [ ] WS `wss://xmpp.nixg.ru` → HTTP 101 (переключение протокола)
- [ ] `docker logs icq-prosody` без новых ошибок; компонент `telegram.nixg.ru` аутентифицирован
@@ -0,0 +1,68 @@
# Spec Delta — icq-services
## ADDED Requirements
### Requirement: Жизненный цикл сервисов — только docker compose
Все сервисы проекта /opt/icq (prosody, webchat, slidgram) управляются исключительно
через `docker compose up -d --force-recreate <service>`, а не ручными `docker start`
или `docker create`. Каждый сервис подключён к сети `icq_default` и резолвится по
имени сервиса (DNS-алиас из compose) внутри этой сети.
#### Scenario: prosody запущен штатно через compose
- **GIVEN** сервис prosody пересоздан командой `docker compose up -d --force-recreate prosody`
- **WHEN** выполняется `docker ps --format '{{.Names}} {{.Networks}}'`
- **THEN** у `icq-prosody` непустая колонка Networks, содержащая `icq_default`
#### Scenario: prosody подключён к сети icq_default
- **GIVEN** контейнер prosody в сети icq_default
- **WHEN** выполняется `docker network inspect icq_default`
- **THEN** в списке контейнеров есть `icq-prosody` с IPv4-адресом из 172.27.0.0/16
#### Scenario: резолвинг имени из веб-чата
- **GIVEN** контейнер веб-чата в той же сети
- **WHEN** выполняется `docker exec icq-webchat getent hosts icq-prosody`
- **THEN** возвращается IP 172.27.0.x (просоди виден из веб-чата)
## MODIFIED Requirements
### Requirement: Доступность веб-чата chat.nixg.ru
Контейнер `icq-prosody` имеет IP-адрес в сети `icq_default` и доступен из
`icq-webchat` по имени `icq-prosody`; веб-клиент Converse.js подключается к
wss://xmpp.nixg.ru без бесконечной загрузки.
#### Scenario: веб-клиент открывается
- **GIVEN** prosody в сети icq_default и доступен из webchat
- **WHEN** браузер открывает https://chat.nixg.ru
- **THEN** страница Converse.js загружается и показывает форму входа
(не бесконечная загрузка)
#### Scenario: WebSocket-сессия устанавливается
- **GIVEN** веб-клиент открыт
- **WHEN** Converse.js соединяется с wss://xmpp.nixg.ru
- **THEN** handshake завершается HTTP 101 и появляется форма входа
### Requirement: Мост Telegram (Slidge)
Компонент `telegram.nixg.ru` продолжает аутентифицироваться с prosody
(external component XEP-0114, порт 5347) после пересоздания prosody; данные моста
(./slidgram/data) не затрагиваются.
#### Scenario: компонент аутентифицирован после пересоздания
- **GIVEN** prosody пересоздан через compose
- **WHEN** выполняется `docker logs icq-prosody --tail 100`
- **THEN** в логах нет ошибок аутентификации, компонент telegram.nixg.ru
в списке активных (или нет критических ошибок)
#### Scenario: мост жив после пересоздания
- **GIVEN** prosody пересоздан через compose
- **WHEN** выполняется `docker logs icq-slidgram --tail 50`
- **THEN** нет ошибок подключения/аутентификации; мост в статусе Up
@@ -0,0 +1,42 @@
# Tasks — icq-fix-prosody-network
## 1. Снимок состояния до изменений
- [ ] Зафиксировать `docker ps --format '{{.Names}} {{.Networks}}'` (пустая сеть у prosody)
- [ ] Зафиксировать `docker network inspect icq_default` (webchat, slidgram — без prosody)
- [ ] Снимок контейнера: `docker inspect icq-prosody > /tmp/icq-prosody-inspect-before.json`
## 2. Пересоздание prosody через compose
- [ ] `cd /opt/icq && docker compose up -d --force-recreate prosody`
- [ ] Дождаться `Up` (status), зафиксировать `docker ps` для prosody
## 3. Проверка сети (внутри compose)
- [ ] `docker ps --format '{{.Names}} {{.Networks}}'` → prolody в icq_default
- [ ] `docker network inspect icq_default` → контейнер icq-prosody с IP (172.27.0.x)
- [ ] `docker exec icq-prosody hostname -i` → непустой адрес
- [ ] `docker exec icq-webchat getent hosts icq-prosody` → резолвится (172.27.0.x)
- [ ] `docker exec icq-slidgram getent hosts icq-prosody` → резолвится
## 4. Проверка приложения и логов
- [ ] `docker logs icq-prosody --tail 100` — нет новых критических ошибок,
компонент telegram.nixg.ru аутентифицирован (или в активных)
- [ ] `docker logs icq-webchat --tail 50` — страница отдаётся без ошибок
- [ ] `docker logs icq-slidgram --tail 50` — без ошибок аутентификации
- [ ] `curl -i` внутренний на prosody:5280 (BOSH/WS) → ответ сервера (не refused)
- [ ] `docker compose ps` → все 3 сервиса Up, без Exited/Restarting
## 5. Проверка снаружи (chat.nixg.ru)
- [ ] `curl -i https://chat.nixg.ru/` → HTTP 200 (страница Converse)
- [ ] WS wss://xmpp.nixg.ru → HTTP 101 Switching Protocols
- [ ] (если доступен браузер) chat.nixg.ru открывается, форма входа видна,
без бесконечной загрузки
## 6. Итог и документация
- [ ] Записать результат в /opt/icq/STATUS.md (секция «Что работает» + журнал инцидента)
- [ ] Зафиксировать вывод `docker compose ps` и проверок в коммит-сообщение
- [ ] Обновить WALKTHROUGH.md при необходимости (грабли: ручной запуск вне compose → потеря сети)