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

182 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/sitemap** — `sitemap-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...`
### Вручную
```bash
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.ru``nginx/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 минуту:
```bash
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/` есть кнопка «Отозвать согласие».
## Локальная разработка
```bash
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 недели на наблюдение).