Files
pushkinohistory-ru-v2/CLAUDE.md
striker cf17c6e432
All checks were successful
deploy / deploy (push) Successful in 47s
docs: CLAUDE.md полностью под Astro v2
2026-05-21 03:36:17 +03:00

10 KiB
Raw Blame History

pushkinohistory.ru — Astro v2

Сайт «История города Пушкино». Редизайн с WordPress (v1) на статический Astro 5 + Content Collections + markdown.

Прод: https://pushkinohistory.ru Репо: git.striker.su/striker/pushkinohistory-ru-v2 Хост: web.hhivp.com (45.10.53.206 / 45.10.53.242) Контейнер: pushkinohistory-ru-v2 на 127.0.0.1:4146 (nginx:alpine + Astro SSG) Cutover: 2026-05-21 со старого WP-контейнера pushkinohistory-ru:4143

Стек

  • Astro 5 + Content Collections + markdown
  • nginx:1.29-alpine в runtime-контейнере (статика + bind-mount для агрегатора новостей)
  • sanitize-html — очистка тела поста для RSS <content:encoded> (с CDATA)
  • fast-xml-parser — изолированно в scripts/ (только для cron-агрегатора)
  • sharp (devDep, опц.) — генерация OG-image PNG из SVG
  • PT Serif (заголовки/тело статьи) + IBM Plex Sans (UI)
  • @astrojs/sitemapsitemap-index.xml автоматически

Структура

src/
├── content/
│   ├── posts/*.md          (7 постов, мигрированы из WP DB ph_posts)
│   ├── pages/*.md          (4 страницы: Главная-приветствие, История, Фото, Форум)
│   └── _categories.json    (через categorySlugs в frontmatter)
├── components/
│   ├── Header.astro        (фото-шапка + аэрофото Пушкино + sepia overlay)
│   ├── Sidebar.astro       (Транспорт, Рубрики с подсчётом, Партнёры, Объявления)
│   ├── Footer.astro
│   ├── PostCard.astro      (featured / has-thumb / no-thumb варианты)
│   ├── CookieConsent.astro (152-ФЗ баннер, ph-consent в localStorage+cookie)
│   └── Analytics.astro     (Яндекс.Метрика + GA, gating через type=text/plain)
├── layouts/BaseLayout.astro
├── pages/
│   ├── index.astro         (Главная история + Ещё из истории + Хроника)
│   ├── [slug].astro        (один пост или одна страница)
│   ├── cat/[slug].astro    (рубрика)
│   ├── cat/[slug]/feed.xml.ts  (per-category RSS)
│   ├── news.astro          (агрегатор внешних RSS, фетчит /api/news.json)
│   ├── 404.astro
│   ├── privacy.astro       (политика + кнопка «Отозвать согласие»)
│   ├── feed.xml.ts         (общий RSS, с RSS_CUTOFF)
│   └── sitemap.txt.ts      (plain-text карта)
├── lib/
│   ├── extract.ts          (firstImage, plainText, formatDateRu)
│   └── rss-helpers.ts      (buildRss, sanitizeForRss, cdata, plainTextExcerpt)
├── data/                   (внешний контент-конфиг, JSON)
│   ├── transport.json      (ссылки на Yandex.Schedules / mostransport)
│   ├── partners.json
│   ├── ads.json
│   └── feeds.json          (внешние RSS-источники для cron-агрегатора)
├── styles/global.css
└── consts.ts               (SITE_TITLE, MAIN_NAV, RSS_CUTOFF, ANALYTICS, plural)

public/
├── uploads/                (6 картинок, перенесены из WP /wp-content/uploads/)
├── favicon.svg
├── robots.txt
├── ai.txt
└── llms.txt

nginx/pushkinohistory.ru.conf   (vhost для хост-nginx, симлинкуется в /etc/nginx/conf.d/)

scripts/
├── convert_posts.py        (WP DB → src/content/posts.json + pages.json, fix WP-resized URL)
├── convert_to_markdown.py  (posts.json → src/content/posts/*.md с frontmatter)
├── pull-external-rss.mjs   (cron на хосте: feeds.json → data/news.json)
├── install-cron.sh         (установка cron на web.hhivp.com)
└── package.json            (изолированный fast-xml-parser)

Dockerfile          (multi-stage: node:22-alpine build → nginx:1.29-alpine serve)
nginx.conf          (внутри контейнера: gzip, кэш _astro/, MIME для RSS, /api/news.json из bind-mount)
docker-compose.yml  (контейнер на 127.0.0.1:4146, bind-mount data/ → /var/lib/pushkino/data:ro)
.gitea/workflows/deploy.yml  (push в main → SSH-деплой на web.hhivp.com)

Контент

  • 7 постов + 4 страницы скрейпом из WP DB pushkinohistory_ru на db.hhivp.com
  • URL-encoded кириллические slug'и WP → транслитерированы (/segodnya-nochyu-rossiyane-uvidyat-pervoe/); старые URL → 301 через nginx map по $uri
  • WP-resized URL (-1024x768.png) → оригинал автоматически в convert_posts.py:RESIZED_RE
  • Frontmatter-флаги для иерархии главной:
    • featured: true + featuredImage — пин на верх как «Главная история» (Воронино, Старое Село)
    • hideFromList: true — скрыть с главной (3 «технические работы»), доступ только через рубрику
  • Категория main — псевдо-флаг «попадает на главную»; не показывается в плашках и в сайдбаре

RSS

Свой /feed.xml (для IPB Importer)

  • Полный HTML тела поста в <content:encoded> с CDATA (sanitize-html → buildRss)
  • Стабильные <guid isPermaLink="true"> = URL поста (IPB дедуплицирует)
  • <dc:creator>, <category>, корректный <pubDate> в RFC-822
  • Контент-Type application/rss+xml; charset=utf-8
  • RSS_CUTOFF в src/consts.ts (default 2010-01-01) — отрезает старый архив. Чтобы IPB не флудил при следующем рестарте — поменять на новую дату и пересобрать
  • Per-category RSS: /cat/<slug>/feed.xml

Агрегатор внешних RSS

  • src/data/feeds.json — список источников (enabled: false по умолчанию)
  • scripts/pull-external-rss.mjs — cron на web.hhivp.com (каждый час в :12)
  • Пишет /opt/docker/sites/pushkinohistory-ru-v2/data/news.json (bind-mount в контейнер как /var/lib/pushkino/data:ro)
  • Фронт /news/ фетчит client-side через /api/news.json (отдаёт nginx внутри контейнера alias на bind-mount)
  • Логи /var/log/pushkino-rss-aggregator.log + logrotate weekly × 4

Чтобы добавить источник:

  1. В src/data/feeds.json добавить {name, url, enabled: true, max}
  2. Push → CI → деплой
  3. На следующем cron-tick'е появится в /news/

Деплой

Автоматический (Gitea Actions)

Push в main.gitea/workflows/deploy.yml:

  1. SSH на web.hhivp.com с ключом из секрета SSH_DEPLOY_KEY
  2. git fetch + reset --hard origin/main
  3. docker compose build && up -d
  4. curl -fsS http://127.0.0.1:4146/ — health check
  5. docker image prune --filter "until=168h"

Секреты в Gitea (/repos/striker/pushkinohistory-ru-v2/actions/secrets):

  • SSH_DEPLOY_KEY — приватный ключ ~/.ssh/pushkino-v2-deploy (генерён локально, pubkey в striker@web:~/.ssh/authorized_keys)
  • SSH_KNOWN_HOSTS — fingerprint web.hhivp.com ssh-ed25519 AAAAC3...

Вручную

cd E:\Projects\pushkinohistory-ru-v2
git add . && git commit -m "..." && git push
# или с локалки на сервер:
ssh striker@web.hhivp.com 'cd /opt/docker/sites/pushkinohistory-ru-v2 && git pull && docker compose up -d --build'

nginx vhost

Симлинк: /etc/nginx/conf.d/pushkinohistory.runginx/pushkinohistory.ru.conf в репо. После правки nginx-конфига: push → CI заберёт → sudo nginx -t && sudo systemctl reload nginx.

301-редиректы со старых WP-URL — через map $uri $legacy_redirect (см. файл). Если нужно добавить новый редирект — отредактировать map и pushнуть.

Откат на WP v1

Старый WP-контейнер pushkinohistory-ru:4143 + БД pushkinohistory_ru на db.hhivp.com сохранены. Откат за ~1 минуту:

ssh striker@web.hhivp.com
echo "Gh_lpx2017!" | sudo -S ln -sfn /opt/docker/sites/pushkinohistory-ru/nginx/pushkinohistory.ru.conf /etc/nginx/conf.d/pushkinohistory.ru
sudo nginx -t && sudo systemctl reload nginx

После 1-2 недель стабильной работы v2 — старый WP можно удалить (контейнер + БД + репо).

Форум

forum.pushkinohistory.ru — IPB 4.x в отдельном контейнере forum-pushkinohistory-ru:4144. v2 редизайном не затронут.

Аналитика

ANALYTICS в src/consts.ts (yandexMetrika, googleGtag) пустые — впишите ID после регистрации счётчиков. Скрипты в Analytics.astro имеют type="text/plain" data-cookieconsent="statistics" и активируются только после согласия в баннере CookieConsent.astro.

Согласие хранится в localStorage + cookie ph-consent (12 мес). На /privacy/ есть кнопка «Отозвать согласие».

Локальная разработка

npm install
npm run dev      # → http://localhost:4321
npm run build    # → dist/ (статика)
npm run preview

Если 4321 занят — Astro сам найдёт следующий свободный (4322 и т.д.).

История

  • 2026-05-08: v1 (WordPress 6.x) контейнеризован, миграция со str-u-01 на web.hhivp.com
  • 2026-05-14: фикс trust-proxy.conf для Docker bridges (Better WP Security)
  • 2026-05-21: v2 редизайн — Vite+React → Astro 5 (стек как у anotherreflections-website-v2). Cutover, бэкап старого WP в репо pushkinohistory-ru + БД на db.hhivp.com (~2 недели на наблюдение).