Initial import: vesti.nixg.ru — новостной апрув-проект (web, crawler, classifier, publisher, openspec)

This commit is contained in:
kpa39l
2026-09-13 15:58:32 +00:00
commit c3f59f7b7a
113 changed files with 7065 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# AGENT.MD — Правила проекта VESTI
## Правило №1: ВСЕ изменения — через OpenSpec
- **Любое изменение проекта (багфикс, фича, рефакторинг, конфиг, деплой, docs) оформляется как отдельный change** в `/opt/vesti/openspec/changes/<change-name>/`.
- **НЕ начинать правки кода/файлов, пока change не создан и не провалидирован (`openspec validate` чисто).** Это обязательное требование (у VESTI нет бэкапа — OpenSpec фиксирует состояние и откат).
- **Сразу после правок — обновить STATUS.md/TODO.md и сделать бэкап** (см. «Бэкап» ниже).
- Формат change (как в образцах `tg-crawler-publisher-prototype`, `publisher-service`):
- `.openspec.yaml` (schema: spec-driven, created: дата)
- `proposal.md` — зачем (проблема пользователя)
- `design.md` — как (дизайн, точные правки)
- `tasks.md` — чеклист задач; отмечать `[x]` при выполнении
- CLI `openspec change new` НЕ существует → change создаётся вручную (mkdir + файлы по образцу).
- Проверка: `openspec validate <change-name>` — должно быть чисто.
- После подтверждения пользователем change архивируется.
- Не начинать правки кода, пока change не создан и не провалидирован.
## Стек и архитектура
- Новостной агрегатор: TG-краулер → классификатор (Ollama qwen3:8b-nothink) → веб-модерация → публикация в Telegram.
- `vesti-web` (FastAPI+Jinja2, :8400, systemd-юнит) --HTTP POST--> `publisher-service` (FastAPI, Docker-контейнер, :8410) --Bot API (SOCKS5 127.0.0.1:1080)--> Telegram @dedinit_vesti.
- БД: SQLite `/opt/vesti/db/vesti.db` — открывать с WAL + busy_timeout (иначе `database is locked` при фоновом классификаторе).
- Фронтенд: **без внешних CDN** (никаких unpkg/jsdelivr). Bootstrap локален: `web/static/bootstrap.min.css`, htmx запрещён. approve/reject — обычные POST-формы.
- Markdown в шаблонах — фильтр `| markdown` (XSS-safe: escape → nl2br → sane_lists). Сырой вывод текста запрещён.
- Даты в UI — фильтр `| dt` → `ЧЧ:ММ ДД.ММ.ГГГГ` (не ISO `[:16]`).
- Пути бандлов: в БД `published.bundle_path` хранится **относительный** путь от `bundles/` (напр. `linux/2026-09/slug.md`), ссылка в UI `/bundle/<rel>`. Абсолютные пути запрещены (баг двойного слэша — исправлен).
## Секреты и .env
- `.env` в корне (chmod 600). Переменные: `ADMIN_USER`, `ADMIN_PASSWORD` (веб-логин), `VESTI_BOT_TOKEN`, `VESTI_BOT_CHANNELS`, `TG_PROXY`, `PUBLISHER_URL`, api_id/api_hash.
- Значения секретов НЕ показывать, НЕ сохранять, НЕ коммитить (пишется только имя переменной).
- `.env.example` — всегда актуализировать при добавлении переменной.
## Правила работы
- **Не удалять пользовательские файлы.** Перезапись/перемещение — только после явного подтверждения пользователя.
- Дедуп постов: sha256(text) + url. Физически ничего не удаляем — только смена `status`.
- Общение с пользователем — на русском, кратко (статусы), без «всё ок».
- Все ресурсы проекта — в `/opt/vesti` (ничего в домашней директории).
- Документация проекта: STATUS.md (живой), PRD.md, TODO.md, WALKTHROUGH.md — поддерживать актуальными; при закрытии сессии обновлять.
- Ссылки и доступы к ресурсам (URL/SSH/пути) фиксировать в файлах проекта.
## Запуск / проверка
```bash
cd /opt/vesti
sudo systemctl restart vesti-web # веб :8400 (0.0.0.0, uvicorn web.app:app)
docker compose -f services/publisher/docker-compose.yml up -d --build # publisher :8410
curl -s http://127.0.0.1:8410/healthz # ok, bot=dedinit_controller_bot, proxy, channels
.venv/bin/python -m crawler.telegram_crawler --all # краулер (инкрементально)
CLASSIFY_TIMEOUT=20 .venv/bin/python -m classifier.classify --db db/vesti.db --limit 200
openspec validate <change-name> # валидация change
```
- Внешний доступ: https://vesti.nixg.ru (Caddy на VPS02: /opt/caddy/Caddyfile, reverse_proxy 10.8.0.2:8400).
## Направления (directions)
linux, tech, politics, games, electronics, llm. Свой канал @dedinit — источник `own: true`, посты is_own=1, fan-out по направлениям с атрибуцией «Дед в АйТи».
## Бэкап (ОБЯЗАТЕЛЬНО, у VESTI нет собственного бэкапа)
- Скрипт: `/opt/vesti/backup.sh` (по образцу `/opt/icq/backup.sh`): архивирует проект → `/opt/vesti/backups/vesti_<дата>.tar.gz`, копирует на Яндекс.Диск `/mnt/yandex-disk/backup/vesti-backups/`.
- Хранение: локально 7 дней, на ЯД 30 дней (ротация в скрипте).
- Запуск: root cron `45 2 * * *` (как у icq). ЯД монтируется автоматически (fstab davfs + @reboot).
- **После ЛЮБЫХ изменений проекта** (или по требованию) — запустить `sudo /opt/vesti/backup.sh` и проверить, что архив появился в `/mnt/yandex-disk/backup/vesti-backups/`.
- Проверка: `ls -lh /opt/vesti/backups/ | tail -3` и `ls -lh /mnt/yandex-disk/backup/vesti-backups/ | tail -3`.