bingo: build the card from chosen providers
Let visitors tick providers (Yandex, IXcellerate, RTK-DC, Sber, …) and get the usual 5×5 card made of only those providers' datacenters, first 25 in ranking order, with lines scored as normal. A selection with fewer than 25 sites leaves the rest of the card empty, so the card is always 5×5. Each provider chip shows crossed/total for the current view. Datacenters get a provider slug, backfilled from the free-text operator, guessed for new rows and editable in the admin. Filtered URLs are noindex with canonical to the plain card. Assisted-by: Claude:opus-5
This commit is contained in:
parent
9ba108b6b0
commit
c64098813b
9 changed files with 155 additions and 8 deletions
|
|
@ -131,6 +131,7 @@ A second public site served from the **same process** on `BINGO_HOST` (`datacent
|
|||
- 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".
|
||||
- Status: operational | building | planned. `mw_type` (it | connected | total | design | mva, NULL = not stated) tags the MW figure in the dialog; mva swaps the unit.
|
||||
- Views: the bare locale URL is the **operational** card (default, indexed); `?view=all` adds construction/planned projects in the same ranking with lines recomputed, and is noindex with canonical to the bare URL. The admin dashboard tile shows the operational card too.
|
||||
- Provider filter: `bingo_datacenters.provider` (a `Bingo::PROVIDERS` slug; migration 016 backfilled it from `operator`, `Bingo.guess_provider` fills new rows, editable in admin). `?p[]=yandex&p[]=rtk` (or `?p=yandex,rtk`) builds the usual 5×5 card from only those providers' datacenters, first 25 by position; a smaller selection leaves empty cells. Filtered URLs are noindex with canonical to the bare page; language and view links keep the selection.
|
||||
- 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), `-1200.webp` (dialog, JSON-LD) and `-og.jpg` (1200×630 centre crop, og:image); `photo_variants`/`photo_og` record success (rows without `photo_og` use the 1200 WebP as og:image) 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`, `/sitemap.xml` (hreflang alternates, `lastmod` = max `updated_at`), and favicon/apple-touch-icon routes serving `assets/bingo/`. The h1 carries a per-locale `tagline`; `/en/` 301s to `/en`. Per-locale `seo_title`/`seo_desc` with the live score, OG/Twitter tags (og:image = latest hit's photo, alt = its name and city), JSON-LD WebSite + ItemList of Places (`info_url` as `subjectOf`, incidents as `event`). HSTS via Rack::Protection. Canonical/hreflang always use `BINGO_HOST`, so `BINGO_ALT_HOST` doesn't compete.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue