datacenterbingo/CLAUDE.md
Sergei Poljanski 9c8606fbac
All checks were successful
Build and Deploy to Production / test (push) Successful in 17s
Build and Deploy to Production / build (push) Successful in 50s
Build and Deploy to Production / deploy (push) Successful in 36s
Read photos from the datacenterbingo-photos bucket
The photos moved out of asxpio's invoice bucket into their own (storage
repo); keys are unchanged.

Assisted-by: Claude:opus-5
2026-10-12 04:09:01 +04:00

3 KiB
Raw Blame History

datacenterbingo

Public site for datacenterbingo.xyz: a 5×5 bingo card of Russia's largest datacenters, crossed out on publicly sourced incidents. Ruby/Sinatra, read-only. Primary repo git.czsk.it/asxpi/datacenterbingo (Forgejo, CI and deploy); github.com/asxpi/datacenterbingo is a push mirror.

Shared with asxpio

Content is edited in the asxp.io admin (/admin/bingo, repo asxpio: lib/bingo.rb, lib/bingo_admin.rb). Both apps use the same Postgres tables (bingo_datacenters, bingo_incidents) and the photos under bingo/ in the datacenterbingo-photos bucket (asxpio's admin uploads them there).

  • asxpio owns the schema. Migrations live there. After it adds a bingo migration, refresh test/schema.sql (instructions in its header) and update the models here.
  • lib/bingo.rb here is the read side of asxpio's: models, Board, PROVIDERS, the T UI strings, and photo/IndexNow key reading. The admin side (writes, photo upload and resizing, IndexNow pings, ranking, seeding, guess_provider) stays in asxpio. Keep shared parts in step: PROVIDERS, Board, and model methods.
  • Prod uses a read-only DB role bingo (SELECT on the two tables) and a MinIO user limited to s3:GetObject on datacenterbingo-photos. Both are provisioned by the storage repo (init/), from the same BINGO_* secrets set on both repos.

Layout

  • app.rb: BingoWeb. Routes: / (redirect by Accept-Language), /ru|en|uk (card; ?view=all, ?p[]=provider), /:locale/dc/:slug, /sitemap.xml, /robots.txt, /p/:file (photo proxy, immutable), /<indexnow-key>.txt, icons, /healthz.
  • config.ru: www. → BINGO_HOST 301.
  • views/: layout.erb (CSS and SEO head), index.erb (card, provider filter, dialogs), dc.erb, partials. assets/: icons.
  • Card rules: always 5×5. The bare locale URL is the operational card (indexed). ?view=all and provider-filtered URLs are noindex, with canonical pointing to the bare page.

Dev and tests

nix develop, then bin/test. That provisions an ephemeral Postgres and loads test/schema.sql. Run cp .env.example .env for a local server (rackup), pointing it at a DB that has the bingo tables.

Deploy

On push to main, .forgejo/workflows/deploy.yaml tests, builds with kaniko to $FJ_REGISTRY/$FJ_USER/datacenterbingo, then over SSH writes /opt/datacenterbingo/{docker-compose.yml,.env} and runs docker compose up -d. The container is on the traefik and storage networks, and the Traefik router datacenterbingo takes BINGO_HOST and www..

Secrets:

Secret Purpose
FJ_REGISTRY, FJ_USER, FJ_TOKEN kaniko clone + push (write:package, read:repository); Forgejo reserves the FORGEJO_ prefix
DEPLOY_IP, DEPLOY_USER, DEPLOY_SSH_KEY SSH to prod
BINGO_DB_PASSWORD read-only Postgres role bingo
BINGO_S3_ACCESS_KEY, BINGO_S3_SECRET_KEY read-only MinIO user
INDEXNOW same key as asxpio's INDEXNOW (served here, pinged from there)