diff --git a/README.md b/README.md index c0551a1..368372f 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,80 @@ # Teletype Games -Monorepo: Vue 3 frontend + Rails 8 API. +Monorepo for the Teletype Games portal: a Vue 3 frontend, a Rails 8 API host app, +and the reusable **WarpEngine** software-catalog engine. -## Projekt struktúra +## Project structure ``` apps/ - frontend/ # Vue 3 + Vite + TypeScript + Tailwind - api/ # Rails 8 API + ActiveAdmin + 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) ``` -## Fejlesztői környezet +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 `/update` endpoint, the public read-only JSON API + (`/api/software*`, `/api/builds*`, `/api/image`, `/api/download`, `/file/*`) + and the catalog ActiveAdmin resources. See its [README](libs/ruby/warp_engine/README.md). +- **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 ```bash docker compose up -d ``` -| Szolgáltatás | URL | +| Service | URL | |---|---| | Frontend | `http://${WEBAPP_DOMAIN}` | | API | `http://${WEBAPP_DOMAIN}/api` | | Admin | `http://${WEBAPP_DOMAIN}/admin` | -| API Docs | `http://${WEBAPP_DOMAIN}/api/swagger` | +| 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 + +```bash +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: + +```bash +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) ```bash -# Ellenőrzés -docker compose run --rm --no-deps api bundle exec rubocop - -# Automatikus javítás -docker compose run --rm --no-deps api bundle exec rubocop -A +docker compose run --rm --no-deps api bundle exec rubocop # check +docker compose run --rm --no-deps api bundle exec rubocop -A # autofix ``` -Konfig: `apps/api/.rubocop.yml` (rubocop-rails-omakase preset) +Config: `apps/api/.rubocop.yml` (rubocop-rails-omakase preset) ### Frontend (ESLint) ```bash -# Ellenőrzés -docker compose run --rm --no-deps frontend npm run lint - -# Automatikus javítás -docker compose run --rm --no-deps frontend npm run lint:fix +docker compose run --rm --no-deps frontend npm run lint # check +docker compose run --rm --no-deps frontend npm run lint:fix # autofix ``` -Konfig: `apps/frontend/eslint.config.js` (ESLint 9 flat config, Vue + TypeScript) +Config: `apps/frontend/eslint.config.js` (ESLint 9 flat config, Vue + TypeScript) diff --git a/libs/ruby/warp_engine/README.md b/libs/ruby/warp_engine/README.md index 346da0d..9c59a0e 100644 --- a/libs/ruby/warp_engine/README.md +++ b/libs/ruby/warp_engine/README.md @@ -1,24 +1,29 @@ # WarpEngine -Mountable Rails engine: retro szoftverkatalógus CI-pipeline-ból hívható release-updaterrel, -publikus read-only JSON API-val és a host adminjába betöltődő ActiveAdmin erőforrásokkal. +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. -## Mit ad +## What it provides -- **Modellek**: `Software`, `Release`, `ReleaseAsset`, `ExternalLink`, `PlatformLink`, - `Image`, `SoftwareImage`, `Download` (mind `WarpEngine::` alatt, prefix nélküli táblákkal) -- **Updater**: `GET /update?platform=&name=&version=` (`X-Update-Secret` fejléc vagy - `?secret=`) — a CI a build-artifactokat a `file_container_path` alá másolja - (`-*` konvencióval), majd meghívja az endpointot; az updater kicsomagol, - metadatát parse-ol, és upserteli a Software/Release/ReleaseAsset/ExternalLink rekordokat. - Támogatott platformok: tic80, ebitengine, love, c64, godot, bevy, phaser. -- **Publikus API**: `/api/software`, `/api/software/highlighted`, `/api/builds`, - `/api/softwares/:name/builds`, `/api/image/:id`, `/api/download?path=`, `/file/*path` -- **Admin**: ActiveAdmin resource-fájlok (softwares a 3 szintű beágyazott formmal, - releases, external links, platform links, images orphan-kezeléssel, Files fájlkezelő - picker móddal, download stats) — a host ActiveAdmin példányába töltődnek be. +- **Models**: `Software`, `Release`, `ReleaseAsset`, `ExternalLink`, + `PlatformLink`, `Image`, `SoftwareImage`, `Download` (all under + `WarpEngine::`, with unprefixed table names) +- **Updater**: `GET /update?platform=&name=&version=` (auth via the + `X-Update-Secret` header or `?secret=`) — CI copies build artifacts under + `file_container_path` using the `-*` 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. -## Telepítés +## Installation ```ruby # Gemfile @@ -26,24 +31,24 @@ gem "warp_engine", path: "../../libs/ruby/warp_engine" ``` ```sh -rails g warp_engine:install # initializer + create_warp_engine_tables migráció +rails g warp_engine:install # initializer + create_warp_engine_tables migration rails db:migrate ``` ```ruby -# config/routes.rb — utolsó sorként, hogy a host route-jai nyerjenek +# config/routes.rb — keep it the last entry so host routes win mount WarpEngine::Engine => "/" ``` -## Konfiguráció +## Configuration ```ruby 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 mindig elutasít - # Ha a host modelljei is használnak katalógus-képeket: + c.update_secret = ENV["UPDATE_SECRET"] # nil => /update rejects everything + # If host models also reference catalog images: c.image_owners = [ { label: "member", @@ -55,28 +60,30 @@ Rails.application.config.to_prepare do end ``` -## Host-elvárások +## Host expectations -- **ActiveAdmin + Devise a hostban él**: auth, téma, assetek és a `/admin` route-ok a - host dolga; az engine csak resource-fájlokat ad a `ActiveAdmin.application.load_paths`-hoz. -- **Files picker JS**: a release-asset path-mezők melletti fájlkiválasztó a host - `active_admin.js`-ében élő pár soros JS-re támaszkodik (iframe a - `/admin/files?picker=1&field=` címre) — új hostba ezt is át kell venni. -- **apipie**: ha a host apipie-dokut generál, vegye fel a matcherbe: +- **ActiveAdmin + Devise live in the host**: authentication, theme, assets and + the `/admin` routes are the host's responsibility; the engine only appends + its resource files to `ActiveAdmin.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=`) — 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"`. -## Viselkedési megjegyzések +## Behavioral notes -- Minden modell soft-delete-es (`default_scope { where(deleted_at: nil) }`); az updater - `.unscoped`-dal "feltámasztja" az újra beküldött, korábban törölt rekordokat. -- A JSON-formátum szándékosan bug-kompatibilis az egykori Go backenddel - (Go zero-time timestampek, camelCase kulcsok, legacy flat path mezők). -- Modell-kiterjesztési pontok: `ActiveSupport.on_load(:warp_engine_)` hookok. +- 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_)` hooks. -## Tesztek +## Tests ```sh bundle install -bundle exec rake app:db:prepare RAILS_ENV=test # warp_engine_test DB a dummy apphoz +bundle exec rake app:db:prepare RAILS_ENV=test # warp_engine_test DB for the dummy app bundle exec rspec ```