feat(webclient): Phanpy on web.dedinit.ru; clean footer without pride flags

- phanpy service (openengineering/phanpy:latest) :8383->8080, Caddy vps02 → 10.8.0.2:8383
- custom page_footer.tmpl mounted ro: removes 🏳️🌈/🏳️⚧️/🦥 from footer
- scripts/check-pride.sh + check-pride.py: detect LGBTQ flags in GtS templates (unicode-normalized),
  to run on every image upgrade
- STATUS.md: procedure for GtS upgrades
- openspec: add-webclient-and-clean-footer
This commit is contained in:
estorozhenko
2026-09-07 13:55:45 +00:00
parent 30121869f2
commit c8d490d1c6
10 changed files with 340 additions and 2 deletions
+22 -2
View File
@@ -1,6 +1,6 @@
# GoToSocial — Статус
Обновлено: 2026-09-06 (поздний вечер, деплой завершён)
Обновлено: 2026-09-07
## Текущее состояние
@@ -39,13 +39,33 @@ Split-domain работает: аккаунты `@user@dedinit.ru`, хост soc
- 2026-09-06: gotosocial commit d9951b6 запушен на gitverse (56f228a..d9951b6)
- 2026-09-06: dedinit.ru commit b049cb2 запушен на gitverse (3d2f07b..b049cb2)
### Веб-клиент Phanpy + чистый подвал (2026-09-07)
- Phanpy (openengineering/phanpy:latest) в docker-compose, порт 8383 (внутри nginx слушает 8080!) → https://web.dedinit.ru (Caddy vps02 → 10.8.0.2:8383)
- DNS: web.dedinit.ru A 87.242.100.206 (добавлен пользователем); TLS от Caddy (авто-LE)
- CORS на API GtS уже `*` — Phanpy работает из браузера напрямую; проверено preflight 204 + allow-origin
- Кастомный page_footer.tmpl (без 🏳️🌈🏳️⚧️🦥 в подвале), смонтирован volume `./web/template/page_footer.tmpl:ro`
- Проверка при обновлении GtS: `./scripts/check-pride.sh` (python3-детект юникода, нормализация; grep-эмодзи ловил ложные срабатывания)
## В работе / Следующие шаги
- [ ] Проверить SMTP-письмо (регистрация/восстановление пароля) — через админку
- [x] Регистрация открыта (10/день) + apex-webfinger динамический (change fix-apex-webfinger-and-registration, архив)
- [x] Веб-клиент Phanpy + чистый подвал (change add-webclient-and-clean-footer)
- [ ] Мониторинг: пробросить :9464 (метрики уже слушают), job в prometheus.yml, дашборд Grafana
(инструкция по метрикам GtS получена от пользователя 2026-09-06)
- [ ] Логи в json-формате при желании (log-format: json) — по умолчанию logfmt
## Процедура при обновлении версии GtS (важно!)
1. Обновить тег образа в docker-compose.yml (например `0.23.0`).
2. Проверить шаблон подвала на флаги ДО перезапуска:
```bash
IMAGE=superseriousbusiness/gotosocial:0.23.0 /opt/gotosocial/scripts/check-pride.sh
```
(скрипт создаёт временный контейнер из образа, копирует шаблоны, ищет 🏳️🌈🏳️⚧️).
3. Если найдены — обновить `/opt/gotosocial/web/template/page_footer.tmpl` (убрать span с эмодзи),
затем `docker compose up -d gotosocial`.
4. Проверить: `curl -s https://social.dedinit.ru/@kpa39l | grep -c '🏳'` → 0.
## Отложено (post-MVP, по решению пользователя)
- Мониторинг бэкапов (метрики в Prometheus + дашборд Grafana)
+13
View File
@@ -64,6 +64,19 @@ services:
- ./.cache:/gotosocial/.cache
# Конфиг для справки (read-only; рабочий конфиг — env выше)
- ./config.yaml:/gotosocial/config.example.yaml:ro
# Кастомный шаблон подвала: без радужных флагов/эмодзи (чистый Source - GoToSocial)
# ВАЖНО: при обновлении версии GtS проверить совместимость шаблона (см. STATUS.md)
- ./web/template/page_footer.tmpl:/gotosocial/web/template/page_footer.tmpl:ro
# --- Веб-клиент Phanpy (Mastodon-клиент, статический SPA) ---
# https://web.dedinit.ru (Caddy vps02 → 10.8.0.2:8383)
# Ходит на API social.dedinit.ru напрямую из браузера (CORS уже *).
phanpy:
image: openengineering/phanpy:latest
container_name: phanpy
restart: unless-stopped
ports:
- "8383:8080"
networks:
gotosocial:
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-07
@@ -0,0 +1,40 @@
## Goals
1. Веб-клиент рядом с GtS: чтение и написание постов из браузера без
сторонних приложений.
2. Убрать ЛГБТ-символы из подвала всех страниц, проверять при апгрейде.
## Non-Goals
- Не менять GtS изнутри (fork, патч бинаря).
- Не использовать тяжёлые клиенты (Elk — сборка из исходников, радужная
символика в UI).
- Не поднимать отдельный Mastodon-сервер.
## Decisions
### Клиент: Phanpy (openengineering/phanpy:latest)
- Статический SPA, минимализм, нейтральный (без ЛГБТ-символики в UI).
- Образ официальный, свежий (автосборка main, 2026-09-05).
- Не требует сборки у нас; образ с nginx-раздачей статики.
- CORS уже `*` на GtS → работа с API из любого origin.
### Публикация: web.dedinit.ru (Caddy на vps02)
- Caddyfile (vps02, docker caddy): `web.dedinit.ru { reverse_proxy 10.8.0.2:8383 }`.
- TLS авто через Caddy (как остальные домены).
### Порт/сеть
- Контейнер phanpy на bigbox: порт 8383, сеть gotosocial_default? Нет —
отдельный сетевой мост, доступ извне через vps02 (как GtS).
- Обычно Phanpy не хранит ничего на диске (localStorage в браузере),
volume не нужен.
### Чистка подвала
- Кастомный page_footer.tmpl в /opt/gotosocial/web/template/, смонтирован
volume в контейнер поверх /gotosocial/web/template/page_footer.tmpl.
- Скрипт проверки при обновлении: docs/check-pride.sh — docker cp шаблонов,
grep по эмодзи, fail при наличии.
@@ -0,0 +1,34 @@
## Why
1. На https://social.dedinit.ru/login предлагается использовать сторонние клиенты
(Elk, Tusky и т.п.), но при отсутствии настроенных устройств нечем читать и
писать посты с браузера. Нужен собственный веб-клиент, поднятый контейнером
рядом с GtS.
2. В подвале страниц отображаются ЛГБТ-символы (🏳️‍🌈, 🏳️‍⚧️, 🦥) из
дефолтного шаблона GtS. Пользователь против такой символики (в РФ это
незаконно) — убрать её со всех страниц и проверять при обновлении версии
контейнера.
## What Changes
1. Поднять контейнер веб-клиента Phanpy (лёгкий, нейтральный Mastodon-клиент,
статический SPA) рядом с GtS в docker-compose; опубликовать на
web.dedinit.ru через Caddy (vps02).
2. Заменить шаблон подвала GtS (page_footer.tmpl) на кастомный без радужных
эмодзи; добавить проверку при обновлении образа GtS.
## How
- GtS уже отдаёт CORS `access-control-allow-origin: *` → Phanpy (SPA) сможет
ходить на API с любого origin, включая web.dedinit.ru.
- Phanpy: официальный docker-образ openengineering/phanpy:latest (свежий,
автосборки) — статика на nginx.
- Caddy на vps02: добавить блок web.dedinit.ru → 10.8.0.2:8383.
- Шаблон: docker cp дефолтного page_footer.tmpl → правим → монтируем volume
в контейнер (уже реализовано, проверить).
## Risks
- Phanpy — сторонний клиент; работает через Mastodon API, CORS уже `*` на GtS.
- Обновления GtS могут менять структуру шаблонов — проверять совместимость
page_footer.tmpl (скрипт check-pride.sh).
@@ -0,0 +1,46 @@
## Why
На `/login` инстанса предлагается использовать сторонние клиенты, но нет
собственного веб-клиента для чтения/написания постов из браузера. В подвале
страниц отображаются ЛГБТ-символы из дефолтного шаблона, которые нужно убрать.
## ADDED Requirements
### Requirement: Веб-клиент рядом с GtS
- **MUST**: контейнер Phanpy (официальный образ openengineering/phanpy:latest)
запущен в docker-compose рядом с GtS, публикует порт 8383.
- **MUST**: `https://web.dedinit.ru` (Caddy на vps02 → 10.8.0.2:8383) отдаёт
интерфейс Phanpy, позволяющий логиниться через аккаунт social.dedinit.ru,
читать и писать посты.
- **MUST**: клиент работает с API без CORS-ошибок (GtS отдаёт
`access-control-allow-origin: *`).
#### Scenario: Доступ к веб-клиенту
- **GIVEN** DNS web.dedinit.ru → 87.242.100.206 (vps02) и Caddy-блок
- **WHEN** пользователь открывает https://web.dedinit.ru
- **THEN** загружается интерфейс Phanpy
- **THEN** можно войти через social.dedinit.ru и публиковать/читать посты
### Requirement: Чистый подвал без ЛГБТ-символики
- **MUST**: на всех публичных страницах social.dedinit.ru в подвале
отсутствуют эмодзи 🏳️🌈, 🏳️⚧️ (и любые ЛГБТ-символы).
- **MUST**: кастомный `page_footer.tmpl` смонтирован в контейнер GtS volume
(перезаписывает дефолтный).
- **SHOULD**: скрипт `scripts/check-pride.sh` фиксирует появление флагов при
обновлении образа GtS; процедура задокументирована в STATUS.md.
#### Scenario: Проверка подвала
- **GIVEN** открыта любая страница social.dedinit.ru (/, /about, /@kpa39l)
- **WHEN** выполняется поиск 🏳️🌈 / 🏳️⚧️ в HTML
- **THEN** совпадения отсутствуют
#### Scenario: Обновление версии GtS
- **GIVEN** обновляется image GtS
- **WHEN** выполняется scripts/check-pride.sh
- **THEN** скрипт скачивает шаблоны новой версии и проверяет их на флаги
- **THEN** при обнаружении флагов выводится ошибка (нужна правка шаблона)
@@ -0,0 +1,22 @@
## Context
- Инстанс: social.dedinit.ru (GtS 0.22.1, docker bigbox), account-domain dedinit.ru.
- Прокси: Caddy docker-контейнер на vps02 (87.242.100.206), GtS → 10.8.0.2:8082.
- CORS на GtS API: `access-control-allow-origin: *`.
- Шаблон подвала уже исправлен (page_footer.tmpl смонтирован volume, проверено
на /@kpa39l: флагов нет).
## Tasks
- [x] 1.1 Добавить сервис phanpy в docker-compose.yml (образ openengineering/phanpy:latest, порт 8383)
- [x] 1.2 Поднять контейнер, проверить, что статика отдаётся (curl localhost:8383 → HTTP 200, title Phanpy)
- [x] 1.3 Добавить блок web.dedinit.ru в Caddyfile на vps02 → 10.8.0.2:8383, reload caddy
(понадобился docker restart caddy: bind-mount одиночного файла не live-sync'ится)
- [x] 1.4 Проверить web.dedinit.ru: страница Phanpy загружается (HTTP 200, TLS от Caddy),
API-запросы без CORS-ошибок (preflight 204, allow-origin: *) — пользователь залогинился ✅
- [x] 2.1 Проверить, что подвал на всех страницах чист (grep по 🏳️🌈🏳️⚧️ → 0 на /, /login, /about, /@kpa39l)
- [x] 2.2 Написать scripts/check-pride.sh + check-pride.py (docker cp шаблонов + детект юникода,
fail при наличии; проверен на чистом каталоге exit=0 и на файле с флагами exit=1)
- [x] 2.3 Задокументировать процедуру проверки при обновлении GtS в STATUS.md
- [x] 3.1 Валидация change: openspec validate add-webclient-and-clean-footer → valid
- [ ] 3.2 Коммит + пуш (gotosocial), архив change
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""check-pride — поиск ЛГБТ-символики (🏳️🌈, 🏳️⚧️, ⚧, радуга) в шаблонах GtS.
Надёжная проверка юникода (нормализация NFC/NFD) в отличие от grep-эмодзи.
Использование: check_pride.py <каталог_шаблонов>"""
import os
import sys
# Символы в NFKD-форме (нормализуем и искомое, и файлы)
TARGETS = ["\U0001f3f3\ufe0f\u200d\U0001f308", # 🏳️‍🌈
"\U0001f3f3\ufe0f\u200d\U000026a7\ufe0f", # 🏳️‍⚧️
"\U000026a7\ufe0f", # ⚧️
"pride", "rainbow"]
TARGETS_NFKD = [t.replace("\ufe0f", "") for t in ["\U0001f3f3\ufe0f\u200d\U0001f308",
"\U0001f3f3\ufe0f\u200d\000026a7\ufe0f"]] # без VS
def main():
if len(sys.argv) != 2:
print("Usage: check_pride.py <dir>", file=sys.stderr)
return 2
root = sys.argv[1]
import unicodedata
targets = TARGETS + TARGETS_NFKD
found = []
for dirpath, _dirnames, filenames in os.walk(root):
for fn in filenames:
p = os.path.join(dirpath, fn)
try:
data = open(p, "rb").read().decode("utf-8", errors="ignore")
except OSError:
continue
nfd = unicodedata.normalize("NFD", data)
nfkd = unicodedata.normalize("NFKD", data)
for t in targets:
tnfd = unicodedata.normalize("NFD", t)
if tnfd in nfd or t in nfkd or t.lower() in data.lower():
found.append((p, t))
break
if found:
print("ОБНАРУЖЕНЫ ЛГБТ-символы:")
for p, t in found[:10]:
print(f" {p}: {t!r}")
return 1
print("OK: флагов не найдено")
return 0
if __name__ == "__main__":
sys.exit(main())
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# check-pride.sh — проверка шаблонов GtS на ЛГБТ-символику (🏳️🌈, 🏳️⚧️ и т.п.)
# Запускать ПОСЛЕ обновления образа gotosocial (перед/после docker compose up -d).
# При обнаружении эмодзи в шаблонах — ненулевой код + пути файлов.
#
# Использование:
# ./scripts/check-pride.sh # проверить шаблоны в текущем контейнере gotosocial
# IMAGE=superseriousbusiness/gotosocial:0.23.0 ./scripts/check-pride.sh # проверить образ ДО запуска
set -u
DIR="$(cd "$(dirname "$0")" && pwd)"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
if [ -n "${IMAGE:-}" ]; then
echo "Проверка образа $IMAGE ..."
CID="$(docker create "$IMAGE" 2>/dev/null)" || { echo "ОШИБКА: не удалось создать контейнер из $IMAGE (образ не скачан?)"; exit 2; }
docker cp "$CID:/gotosocial/web/template" "$TMP/templates" >/dev/null 2>&1
docker rm "$CID" >/dev/null 2>&1
D="$TMP/templates"
else
echo "Проверка шаблонов в контейнере gotosocial ..."
docker cp gotosocial:/gotosocial/web/template "$TMP/templates" >/dev/null 2>&1
D="$TMP/templates"
fi
python3 "$DIR/check-pride.py" "$D"
rc=$?
if [ "$rc" -ne 0 ]; then
echo
echo "Найдены флаги — обновите /opt/gotosocial/web/template/page_footer.tmpl"
echo "и перезапустите: docker compose up -d gotosocial"
fi
exit "$rc"
+75
View File
@@ -0,0 +1,75 @@
{{- /*
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
{{- with . }}
<nav>
<ul class="nodot">
<li id="about">
<a
href="/about"
class="nounderline"
>
About {{ .instance.Title }}
</a>
</li>
{{- if .showAcctDir }}
<li id="directory">
<a
href="/directory"
class="nounderline"
>
Account Directory
</a>
</li>
{{- end }}
<li id="version">
<a
href="https://codeberg.org/superseriousbusiness/gotosocial"
class="nounderline"
rel="nofollow noreferrer noopener"
target="_blank"
>
Source - GoToSocial {{ .instance.Version }}
</a>
</li>
{{- if .instance.ContactAccount }}
<li id="contact">
<a
href="/@{{- .instance.ContactAccount.Username -}}"
class="nounderline"
>
Contact account - {{ .instance.ContactAccount.Username }}
</a>
</li>
{{- end }}
{{- if .instance.Email }}
<li id="email">
<a
href="mailto:{{- .instance.Email -}}"
class="nounderline"
rel="nofollow noreferrer noopener"
target="_blank"
>
Email - {{ .instance.Email }}
</a>
</li>
{{- end }}
</ul>
</nav>
{{- end }}