9f806ff57a1f2997af088783a2e104bf440d9c60
- root README: monorepo layout with libs/, the WarpEngine/host layering, rebuild note for the root build context, make api-test and snapshot docs - warp_engine README translated to English Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WarpEngine
Mountable Rails engine: a retro software catalog with a CI-pipeline-callable release updater, a public read-only JSON API, and ActiveAdmin resources that load into the host application's admin.
What it provides
- Models:
Software,Release,ReleaseAsset,ExternalLink,PlatformLink,Image,SoftwareImage,Download(all underWarpEngine::, with unprefixed table names) - Updater:
GET /update?platform=&name=&version=(auth via theX-Update-Secretheader or?secret=) — CI copies build artifacts underfile_container_pathusing the<name>-<version>*naming convention, then calls the endpoint; the updater extracts archives, parses metadata, and upserts the Software/Release/ReleaseAsset/ExternalLink records. Supported platforms: tic80, ebitengine, love, c64, godot, bevy, phaser. - Public API:
/api/software,/api/software/highlighted,/api/builds,/api/softwares/:name/builds,/api/image/:id,/api/download?path=,/file/*path - Admin: ActiveAdmin resource files (softwares with a 3-level nested form, releases, external links, platform links, images with orphan management, a Files file-manager page with picker mode, download stats) — loaded into the host's single ActiveAdmin instance.
Installation
# Gemfile
gem "warp_engine", path: "../../libs/ruby/warp_engine"
rails g warp_engine:install # initializer + create_warp_engine_tables migration
rails db:migrate
# config/routes.rb — keep it the last entry so host routes win
mount WarpEngine::Engine => "/"
Configuration
Rails.application.config.to_prepare do
WarpEngine.configure do |c|
c.file_container_path = ENV.fetch("FILE_CONTAINER_PATH", "/softwares")
c.image_container_path = ENV.fetch("IMAGE_CONTAINER_PATH", "/images")
c.update_secret = ENV["UPDATE_SECRET"] # nil => /update rejects everything
# If host models also reference catalog images:
c.image_owners = [
{
label: "member",
image_ids: -> { Member.where.not(image_id: nil).distinct.pluck(:image_id) },
usage_label: ->(image) { "member" if Member.where(image_id: image.id).exists? }
}
]
end
end
Host expectations
- ActiveAdmin + Devise live in the host: authentication, theme, assets and
the
/adminroutes are the host's responsibility; the engine only appends its resource files toActiveAdmin.application.load_paths. - Files picker JS: the file-picker next to release-asset path inputs relies
on a few lines of JS in the host's
active_admin.js(an iframe pointing at/admin/files?picker=1&field=<dom_id>) — copy that over to a new host too. - apipie: if the host generates apipie docs, add the engine to the matcher:
"#{WarpEngine::Engine.root}/app/controllers/**/*.rb".
Behavioral notes
- Every model is soft-deleted (
default_scope { where(deleted_at: nil) }); the updater "resurrects" re-submitted, previously deleted records via.unscoped. - The JSON shape is intentionally bug-compatible with the former Go backend (Go zero-time timestamps, camelCase keys, legacy flat path fields).
- Model extension points:
ActiveSupport.on_load(:warp_engine_<model>)hooks.
Tests
bundle install
bundle exec rake app:db:prepare RAILS_ENV=test # warp_engine_test DB for the dummy app
bundle exec rspec
Languages
Ruby
100%