mr.zeroandClaude Opus 5 3eedabce43 One /stores page for both stores, with a device chooser
The Batocera store had /batocera to itself. A RetroArch store now serves the same
cartridges on every other machine, and copying the page would have duplicated
everything the two have in common — the framing, the platform table, the engine
links — so they share one page and a Batocera/RetroArch chooser. Only the install
command, the CLI and the uninstall line change with the tab.

/batocera and /retroarch both redirect here with the matching tab preselected,
so old links keep working and the name someone guesses after reading "RetroArch
store" lands somewhere useful. `?device=` makes a link to either half shareable.

The page also documents uninstalling, which it never did, and the five command
blocks share one CommandBlock component instead of repeating the copy button.
The i18n `batocera` block becomes `stores` in both locales; every key the page
uses was checked to exist in both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 08:33:19 +02:00
2026-05-06 20:15:52 +02:00
2026-08-17 08:08:17 +02:00
2026-02-19 12:35:43 +01:00
2026-08-05 20:12:35 +02:00
2026-01-27 20:01:25 +01:00

Teletype Games

Monorepo for the Teletype Games portal: a Vue 3 frontend, a Rails 8 API host app, and the reusable WarpEngine software-catalog engine.

Project structure

apps/
  frontend/            # Vue 3 + Vite + TypeScript + Tailwind SPA
  api/                 # Rails 8 host app: TTG-specific API + ActiveAdmin shell
libs/
  ruby/warp_engine/    # WarpEngine: mountable Rails engine (catalog, updater, admin resources)

The API is split in two layers:

  • WarpEngine (libs/ruby/warp_engine) owns the software catalog: models (softwares, releases, release assets, images, platform links, download stats), the CI-callable /build/* publishing endpoints, the public read-only JSON API (/api/software*, /api/builds*, /api/image, /api/download, /file/*) and the catalog ActiveAdmin resources. See its README.
  • The host app (apps/api) owns everything TTG-specific: members, events, wiki proxy, RSS feeds, Devise/ActiveAdmin authentication, theming and assets. It consumes WarpEngine as a path gem and mounts it at /.

Development environment

docker compose up -d
Service URL
Frontend http://${WEBAPP_DOMAIN}
API http://${WEBAPP_DOMAIN}/api
Admin http://${WEBAPP_DOMAIN}/admin
API docs http://${WEBAPP_DOMAIN}/api/swagger

The api image is built from the repo root (so the libs/ path gems are visible during bundle install) and mounts ./libs at runtime. After changing the compose file or the Gemfile, rebuild with docker compose up -d --build api.

Testing

make api-test

Runs the host suite (apps/api, softwares_test DB), the WarpEngine suite (dummy app, warp_engine_test DB) and a production-mode zeitwerk:check. Individually:

docker exec -e RAILS_ENV=test api bundle exec rspec                                # host
docker exec -w /libs/ruby/warp_engine -e RAILS_ENV=test api bundle exec rspec     # engine

JSON contract baselines for /api/software and /api/builds live in apps/api/spec/snapshots/ — diff against them after refactors.

Linting

Backend (RuboCop)

docker compose run --rm --no-deps api bundle exec rubocop        # check
docker compose run --rm --no-deps api bundle exec rubocop -A     # autofix

Config: apps/api/.rubocop.yml (rubocop-rails-omakase preset)

Frontend (ESLint)

docker compose run --rm --no-deps frontend npm run lint          # check
docker compose run --rm --no-deps frontend npm run lint:fix      # autofix

Config: apps/frontend/eslint.config.js (ESLint 9 flat config, Vue + TypeScript)

S
Description
No description provided
Readme
9.6 MiB
Languages
Ruby 59.4%
Vue 12.6%
TypeScript 12.5%
HTML 10.6%
CSS 2.1%
Other 2.6%