diff --git a/PRD.md b/PRD.md new file mode 100644 index 0000000..a11e7f2 --- /dev/null +++ b/PRD.md @@ -0,0 +1,47 @@ +# GoToSocial — PRD + +## Цель + +Развернуть собственную федиверсную ноду ActivityPub (GoToSocial) на личном домене dedinit.ru — «нода для обычных людей». Аккаунты `@user@dedinit.ru`, сервер на `https://social.dedinit.ru`. + +## Пользователи + +- Владелец (admin): estorozhenko (@estorozhenko@dedinit.ru) +- Приглашённые пользователи («обычные люди») + +## Функциональные требования + +- Инстанс GoToSocial работает в Docker на bigbox (контейнер из /opt/gotosocial) +- Split-domain: `host=social.dedinit.ru`, `account-domain=dedinit.ru` (аккаунты @user@dedinit.ru) +- База данных: SQLite (файл в volume ./data) +- Медиа: локальное хранилище (./data/storage), монтируется в контейнер +- Реверс-прокси: Caddy на vps02 (social.dedinit.ru → 10.8.0.2:8080 через WireGuard) +- TLS: Let's Encrypt автоматически (Caddy) +- SMTP: отправка писем через smtp.jino.ru:587 (STARTTLS), ящик social@dedinit.ru +- Метрики: Prometheus (OTEL экспортёр, /metrics) +- Логи: JSON → Promtail → Loki +- Бэкап: consistent SQLite (VACUUM INTO) + медиа; локально 7 дней, Яндекс.Диск 30 дней + +## Нефункциональные требования + +- Версия GoToSocial фиксируется тегом релиза (v0.22.1), обновление вручную +- Секреты (.env) не попадают в git (в .gitignore) +- host/account-domain НЕ меняются после первого запуска (необратимо) +- Рестарт контейнера: unless-stopped +- Бэкап при недоступном Яндекс.Диске — ошибка (exit != 0), не тихий fail + +## Границы (что НЕ делаем сейчас) + +- Мониторинг бэкапов + дашборд Grafana — **post-MVP** +- Импорт из Telegram — **post-MVP** +- Postgres вместо SQLite — нет (выбор пользователя, обратимо только до старта) +- Remote-медиа не бэкапится (пере-фетчится) + +## Критерии готовности (MVP) + +- [ ] `docker compose up -d` на bigbox — контейнер Up, :8080 отвечает 200 +- [ ] Caddy на vps02: https://social.dedinit.ru отвечает 200, сертификат LE +- [ ] Split-domain: мылтиаккаунт резолвится `acct:estorozhenko@dedinit.ru` (webfinger на apex) +- [ ] SMTP-письмо уходит (подтверждение email) +- [ ] backup.sh запускается, архив на ЯД +- [ ] Админ-аккаунт estorozhenko создан и промоутнут \ No newline at end of file diff --git a/STATUS.md b/STATUS.md new file mode 100644 index 0000000..9756f73 --- /dev/null +++ b/STATUS.md @@ -0,0 +1,55 @@ +# GoToSocial — Статус + +Обновлено: 2026-09-06 (сессия 2026-09-06_19xx) + +## Текущее состояние + +Проект развёртывания GoToSocial-ноды на social.dedinit.ru оформлен: создан каталог /opt/gotosocial, OpenSpec change deploy-gotosocial (валиден), все рабочие файлы (compose, config, .env, backup.sh, README) готовы и запушены в git. **Сервис ещё НЕ запущен** — это следующий шаг. DNS social.dedinit.ru → 87.242.100.206 (vps02) создан пользователем. + +## Сделано + +- 2026-09-06: исследование развёртывания GoToSocial (доки v0.22.1, split-domain, Docker) +- 2026-09-06: каталог /opt/gotosocial, OpenSpec init + change `deploy-gotosocial` (proposal/spec×2/design/tasks), `openspec validate` ✅ +- 2026-09-06: docker-compose.yml (v0.22.1, SQLite, порт 8080, volume ./data, net 172.29.0.0/16) +- 2026-09-06: config.yaml (host=social.dedinit.ru, account-domain=dedinit.ru, SMTP Jino, metrics, log json) +- 2026-09-06: .env (SMTP-пароль; в git исключён), backup.sh (SQLite VACUUM INTO + медиа, ротация 7д/30д, ЯД), README.md, .gitignore +- 2026-09-06: git init + commit d385d8b +- 2026-09-06: gitverse репо `kpa39l/gotosocial` создан (API, Bearer+Accept object+json), main запушен +- 2026-09-06: gitea.nixg.ru pull-mirror `estorozhenko/gotosocial` (интервал 8ч), первая синхронизация ✅ (коммит d385d8b) + +## В работе / Следующие шаги + +- [ ] **Развернуть сервис на bigbox**: `cd /opt/gotosocial && docker compose up -d` + создание админа estorozhenko (нужен пароль от пользователя) +- [ ] **Caddy на vps02**: блок `social.dedinit.ru { reverse_proxy 10.8.0.2:8080 }` + reload (нужен доступ vps02) +- [ ] **Split-domain apex**: .well-known редиректы (webfinger/nodeinfo/host-meta) на dedinit.ru (Jino) — подготовить точные правила +- [ ] Проверить HTTPS (сертификат LE), webfinger, SMTP-письмо, /metrics +- [ ] Настроить cron бэкапа (backup.sh готов; расписание ещё нет) + +## Отложено (post-MVP, по решению пользователя) + +- Мониторинг бэкапов (метрики в Prometheus + дашборд Grafana) +- Дашборд Grafana для GtS +- Импорт из Telegram + +## Как запустить / проверить + +```bash +cd /opt/gotosocial +docker compose up -d +curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/ # 200 +curl -s http://127.0.0.1:8080/metrics | grep -E 'go_goroutines|gin_|bun_' +curl -s 'https://social.dedinit.ru/.well-known/webfinger?resource=acct:estorozhenko@dedinit.ru' +bash backup.sh && ls -lh backups/ +``` + +## Ключевые артефакты + +- /opt/gotosocial/docker-compose.yml, config.yaml, .env, backup.sh, README.md +- /opt/gotosocial/openspec/changes/deploy-gotosocial/ (change) +- gitverse.ru/kpa39l/gotosocial (истина), gitea.nixg.ru/estorozhenko/gotosocial (зеркало) + +## Открытые вопросы + +- Пароль админа estorozhenko для первого запуска +- Готовность vps02 к правке Caddyfile (нужен SSH) +- Точные .well-known редиректы на apex (Jino) — подготовить и применить \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..ad98508 --- /dev/null +++ b/TODO.md @@ -0,0 +1,33 @@ +# TODO — GoToSocial + +Формат: | дата | задача | статус | закрыта в | + +## Открытые + +| 2026-09-06 | Развернуть сервис на bigbox: `docker compose up -d` | 🔵 открыта | | +| 2026-09-06 | Создать админа estorozhenko (gotosocial admin account create --confirmation + promote) | 🔵 открыта | | +| 2026-09-06 | Caddy на vps02: блок social.dedinit.ru → 10.8.0.2:8080 + reload | 🔵 открыта | | +| 2026-09-06 | Split-domain apex: .well-known редиректы (webfinger/nodeinfo/host-meta) на dedinit.ru (Jino) | 🔵 открыта | | +| 2026-09-06 | Проверить HTTPS (сертификат LE), webfinger, SMTP, /metrics | 🔵 открыта | | +| 2026-09-06 | Настроить cron бэкапа (backup.sh готов) | 🔵 открыта | | + +## Post-MVP (отложено) + +| 2026-09-06 | Дашборд Grafana для GoToSocial (метрики) | 🔵 отложено | | +| 2026-09-06 | Мониторинг бэкапов (метрика в Prometheus, дашборд «бэкап создан/лежит локально/ЯД/удалён по ротации») | 🔵 отложено | | +| 2026-09-06 | Импорт из Telegram | 🔵 отложено | | + +## Закрытые + +| 2026-09-06 | Исследование развёртывания GoToSocial v0.22.1 (доки, split-domain, Docker, метрики) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | Каталог /opt/gotosocial + OpenSpec init + change deploy-gotosocial (proposal/spec/design/tasks) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | openspec validate deploy-gotosocial → valid | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | docker-compose.yml (v0.22.1, SQLite, 8080, ./data, net 172.29.0.0/16) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | config.yaml (host/account-domain split, SMTP Jino, metrics, log json) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | .env (SMTP-пароль, в git исключён) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | backup.sh (VACUUM INTO + медиа, ротация 7д/30д, ЯД) | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | README.md, .gitignore | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | git init + commit d385d8b | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | gitverse репо kpa39l/gotosocial (API, Bearer+Accept object+json), push main | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | gitea.nixg.ru pull-mirror estorozhenko/gotosocial (8ч), первая синхронизация | ✅ закрыта | сессия 2026-09-06 | +| 2026-09-06 | Убрать токен из git remote URL (оставить https://kpa39l@gitverse.ru/...) | ✅ закрыта | сессия 2026-09-06 | \ No newline at end of file diff --git a/WALKTHROUGH.md b/WALKTHROUGH.md new file mode 100644 index 0000000..283bf2d --- /dev/null +++ b/WALKTHROUGH.md @@ -0,0 +1,111 @@ +# WALKTHROUGH — GoToSocial (капитанский журнал) + +Хронология реализации. Цель — воспроизводимость с нуля. + +## 2026-09-06 — Инициализация проекта + +### Задача +Развернуть GoToSocial (федiverse-нода ActivityPub) в Docker: /opt/gotosocial, OpenSpec workflow, первое change на развёртывание, git (gitverse истина + gitea зеркало), бэкап на Яндекс.Диск, мониторинг — post-MVP. + +### Решения пользователя (ответы на вопросы) +- БД: SQLite +- Схема: split-domain (host=social.dedinit.ru, account-domain=dedinit.ru), доступ к созданию файлов на apex есть +- Имя инстанса: dedinit.ru; admin: estorozhenko; название сервера: dedinit(); описание: «Нода для обычных людей»; email: kpa39l@yandex.ru +- SMTP: smtp.jino.ru:587 STARTTLS, ящик social@dedinit.ru (пароль в .env) +- Бэкап: SQLite consistent + медиа +- Мониторинг бэкапов/дашборд Grafana/импорт из Telegram — post-MVP +- Метрики/логи: отдельный job (не включать в общий) +- vps02 — только прокси, сервис на bigbox +- Git: последний стабильный тег с фиксацией, ручное обновление +- Секреты в .env, в git исключён +- Первый коммит — сразу с начальными изменениями (не ждать готового сервиса) + +### Исследование +- Документация установки в контейнере (v0.22.1): https://docs.gotosocial.org/en/v0.22.1/getting_started/installation/container/ +- Скачаны refs: ref-container.md, ref-docker-compose.yml, ref-host-account-domain.md, ref-metrics-config.yaml, ref-metrics.md, ref-observability.md, ref-storage.md +- Официальный example docker-compose: https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/example/docker-compose/docker-compose.yaml (важно: путь НЕ example/docker-compose.yml — это 404) +- Метрики: OpenTelemetry → Prometheus: `metrics-enabled: true` + env `OTEL_METRICS_PRODUCERS=prometheus`, `OTEL_METRICS_EXPORTER=prometheus`. Эндпоинт /metrics: go_goroutines, gin_, bun_* +- Логи: log-format: json → promtail → Loki +- Split-domain: аккаунты @user@dedinit.ru при host=social.dedinit.ru; требует .well-known редиректы на apex; НЕОБРАТИМО после старта + +### Инфраструктура (проверено) +- bigbox (10.8.0.2 через WG): сервисы в /opt/, стек мониторинга (Prometheus :9090, Grafana :3001, Loki :3100, node_exporter + textfile /var/lib/prometheus/node-exporter/) +- vps02 87.242.100.206: Caddy 2 (контейнер caddy:alpine, host net), слушает 80/443, паттерн `домен { reverse_proxy 10.8.0.2: }` +- SSH vps02: `ssh -i /mnt/yandex-disk/.ssh_box/cloudruVPS estorozhenko@87.242.100.206` (sudo работает); root/другие ключи НЕ подходят +- Яндекс.Диск: mount /mnt/yandex-disk, бэкапы в /mnt/yandex-disk/backup/-backups/ +- DNS: social.dedinit.ru A → 87.242.100.206 (создан пользователем), apex dedinit.ru → 81.177.135.38 (Jino) + +### OpenSpec workflow +```bash +cd /opt/gotosocial +openspec init --tools hermes --force --no-animation # CLI 1.12.0, бинарь /opt/hermes/.hermes/node/bin/openspec +openspec new change deploy-gotosocial +``` +- config.yaml (context + rules) — инфра-специфичный +- proposal.md, specs/gotosocial-deploy/spec.md + specs/gotosocial-backup/spec.md, design.md, tasks.md +- **Питфол:** OpenSpec требует `#### Scenario:` блоки (GIVEN/WHEN/THEN) ВНУТРИ каждой requirement — просто Verification-блок не проходит validate. Исправлено, `openspec validate deploy-gotosocial` → valid. + +### Рабочие файлы +- docker-compose.yml: image superseriousbusiness/gotosocial:v0.22.1 (фикс. тег), container_name gotosocial, user 1000:1000, restart unless-stopped, env OTEL_METRICS_*, env_file .env, ports 8080:8080, volumes ./data:/gotosocial/storage + ./config.yaml:/gotosocial/config.yaml:ro, network gotosocial 172.29.0.0/16 +- config.yaml: host social.dedinit.ru, account-domain dedinit.ru, protocol https, port 8080, trusted-proxies [127.0.0.1/32, ::1, 172.29.0.1/16], log json, db-type sqlite, db-address /gotosocial/storage/sqlite.db, storage-local-base-path /gotosocial/storage, SMTP smtp.jino.ru:587 (пароль пустой в config — берётся из .env? **TODO: проверить, как GtS читает пароль из env, когда в config.yaml пусто**), metrics-enabled true, instance-title dedinit(), instance-description «Нода для обычных людей», instance-contact-email kpa39l@yandex.ru +- .env: GTS_SMTP_PASSWORD='fF@4guOf9spE2#8$' +- backup.sh: VACUUM INTO → tar.gz (sqlite+storage) + отдельный .env-архив; копия /mnt/yandex-disk/backup/gotosocial-backups/; ротация локально 7д, ЯД 30д; mountpoint-проверка ЯД, exit 1 при ошибке +- README.md, .gitignore (.env, data/, backups/, refs/, openspec/changes/archive/) + +### Git +```bash +cd /opt/gotosocial +git init -b main && git add -A +git -c user.name=estorozhenko -c user.email=kpa39l@yandex.ru commit -m "openspec: change deploy-gotosocial — развертывание GoToSocial (compose+config+backup+docs)" +# d385d8b +``` + +### Создание репозитория gitverse (ВАЖНО — питфолы) +- SSH-ключ gitverse работает: `ssh -i /mnt/yandex-disk/.ssh_box/gitverse git@gitverse.ru` → «Hi kpa39l!» +- push-to-create НЕ включён для пользователей: «Push to create is not enabled» +- Токен из obsidian vault (Gitverse mirror token.md, 40 hex) НЕ работает для API gitverse (400 на всё) — это токен gitea-зеркала +- **Правильный способ — скилл git-forge-management + reference gitverse-api.md:** + - Токен: `source /opt/hermes/.hermes/secrets/git-tokens.env` → GITVERSE_PAT, GITVERSE_API, GITVERSE_LOGIN=kpa39l + - Accept header ОБЯЗАТЕЛЕН: `application/vnd.gitverse.object+json;version=1` (без него 400) +```bash +curl -s -X POST "${GITVERSE_API}/user/repos" \ + -H "Authorization: Bearer ${GITVERSE_PAT}" \ + -H "Accept: application/vnd.gitverse.object+json;version=1" \ + -H "Content-Type: application/json" \ + -d '{"name":"gotosocial","description":"...","private":false,"auto_init":false}' +# HTTP 201, id 327796, full_name kpa39l/gotosocial +``` + +### Push +- Логин аккаунта gitverse = **kpa39l** (не estorozhenko!) +```bash +git remote add origin "https://kpa39l:${GITVERSE_PAT}@gitverse.ru/kpa39l/gotosocial.git" +git push -u origin main +``` +- **Питфол:** токен остался зашит в .git/config — убрано: `git remote set-url origin https://kpa39l@gitverse.ru/kpa39l/gotosocial.git` (creds из git-tokens.env/credential helper) + +### Gitea pull-mirror +```bash +source /opt/hermes/.hermes/secrets/git-tokens.env +curl -s -X POST "${GITEA_API}/repos/migrate" \ + -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" \ + -d "{\"clone_addr\":\"https://oauth2:${GITVERSE_PAT}@gitverse.ru/kpa39l/gotosocial.git\",\"repo_name\":\"gotosocial\",\"repo_owner\":\"estorozhenko\",\"service\":\"git\",\"mirror\":true,\"mirror_interval\":\"8h\"}" +# HTTP 201, mirror=true; затем POST /repos/estorozhenko/gotosocial/mirror-sync → 200 +``` +- **Питфол:** migrate с ssh:// НЕ работает (422 protocol not allowed) — только HTTPS + oauth2:PAT (проверено ранее, см. reference gitea-pull-mirror-gitverse.md) + +### Команды развёртывания (следующий шаг) +```bash +cd /opt/gotosocial && docker compose up -d +docker compose exec gotosocial gotosocial admin account create \ + --username estorozhenko --email kpa39l@yandex.ru \ + --password '<пароль>' --confirmation +docker compose exec gotosocial gotosocial admin account promote --username estorozhenko +``` +Caddy vps02: блок `social.dedinit.ru { reverse_proxy 10.8.0.2:8080 }`, `docker exec caddy caddy reload --config /etc/caddy/Caddyfile` + +## Открытые вопросы / риски +- Как GtS читает SMTP-пароль: config.yaml `smtp-password: ""` + .env `GTS_SMTP_PASSWORD` — проверить при первом запуске, что письма уходят +- Пароль админа estorozhenko — нужен от пользователя +- Доступ к vps02 для правки Caddyfile — нужен (SSH estorozhenko@87.242.100.206 + cloudruVPS ключ) +- .well-known редиректы на apex (Jino) — подготовить правила \ No newline at end of file