bingo: operational-only view of the card

The card mixes facilities in service with construction projects (Sber
Balakovo at #1, MOS7, MOS11, Yandex Vladimir-2), which is fine for a
bingo but not when you want to compare what actually runs today. Add a
toggle that builds the card from operational rows only, in the same
ranking, with bingo lines recomputed for that card. The filtered view is
noindex with canonical to the plain locale URL, so it does not compete
with the main page in search.

Assisted-by: Claude:opus-5
This commit is contained in:
Sergei Poljanski 2026-10-10 06:58:30 +04:00
commit 9e885dd8c1
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
6 changed files with 74 additions and 14 deletions

View file

@ -123,6 +123,7 @@ A second public site served from the **same process** on `BINGO_HOST` (`datacent
- Locales `ru` / `en` / `uk` at `/ru`, `/en`, `/uk`; `/` redirects by `Accept-Language` (fallback `en`). Per-locale DB columns (`name_*`, `city_*`, `title_*`); `ru` is required, others fall back to it. UI strings in `Bingo::T` (`lib/bingo.rb`).
- Tables `bingo_datacenters`, `bingo_incidents` (`db/migrations/004_bingo.rb`) in the asxpio DB. First boot seeds from `db/bingo_seed.json` (verified 2026-10-10, sources in `info_url`) only if the table is empty — after that, edit via admin, not the JSON.
- Admin: `/admin/bingo` on asxp.io (`lib/bingo_admin.rb`, registered into `AsxpioWeb`, so HTTP Basic + CSRF apply). Record/delete incidents; add, edit, delete DCs (delete cascades to incidents); upload a photo or import it from a URL; bulk import missing / re-import all photos from `photo_source_url`; "Sort by MW".
- Views: `?view=operational` builds the card from operational rows only (same ranking, construction projects skipped, lines recomputed); it is noindex with canonical to the bare locale URL.
- Ordering: `position` is dense 1..N (`Bingo.place!` inserts and shifts, `renumber!` after deletes). The card shows positions 1–25; anything beyond is reserve. Slug is fixed at creation (it names photo objects).
- Photos: stored in the existing bucket under `bingo/<slug>-<hex>.<ext>` (no storage-repo change), proxied by `BingoWeb` at `/p/:file` with immutable caching (new upload = new key; old objects are kept). Type sniffed from magic bytes (JPEG/PNG/WebP), 8 MB cap, metadata stripped (GPS!). URL import is https-only, admin-only. On store, ImageMagick (`convert`, installed in the Dockerfile) derives `-480.webp` (card cells) and `-1200.webp` (dialog, og:image); `photo_variants` records success and the page falls back to the original without them. "Rebuild resized photos" in admin re-derives from stored originals.
- SEO: `BingoWeb` has `static` off (public/ is asxp.io's), its own `/robots.txt` and `/sitemap.xml` (hreflang alternates), per-locale `seo_title`/`seo_desc` with the live score, OG/Twitter tags (og:image = latest hit's photo), JSON-LD WebSite + ItemList. Canonical/hreflang always use `BINGO_HOST`, so `BINGO_ALT_HOST` doesn't compete.