EN /HU | Login

Public site

The Teletype Games public platform: one monorepo (services/teletypegames) with the catalog backend (Catalog API) and the retro-styled frontend, run by Docker Compose.

Monorepo layout

TXT
apps/
  frontend/   # Vue 3 + Vite + TypeScript + Tailwind
  api/        # Rails 8 API + ActiveAdmin

docker compose up -d starts the dev environment. Both apps sit under one domain:

Path Serves
/ frontend
/api Catalog API
/admin ActiveAdmin
/api/swagger API docs

Linting: RuboCop (rubocop-rails-omakase) for the backend, ESLint 9 (flat config, Vue + TypeScript) for the frontend.

Catalog API

Rails 8 + MySQL. ActiveAdmin panel (blaze theme, Devise auth), Blueprinter serializers, apipie-rails docs with a browsable Swagger UI. It is the single source of truth for software metadata, releases, members, events and download logs, and it serves images and binaries.

Domain model

Software (name, title, author, desc, story, license, platform, status, highlighted; soft-deleted) has many Releases and ExternalLinks, and images through SoftwareImage (default flag + ordering). A Release holds the version and the cartridge / source / HTML folder / docs folder paths. Every download is a Download row (IP, user agent, referer, release), surfacing as downloadCount / totalDownloads in API responses.

Endpoints

Endpoint Purpose
GET /api/software Catalog listing: software + sorted releases + latestRelease (skipping dev-) + webPlayableRelease + totalDownloads
GET /api/software/highlighted Featured software
GET /api/events Community events
GET /api/members Team members
GET /api/stores Store registry (see below)
GET /api/image/:id Image serving
GET /api/wiki/pages?tag=blog\|howto[&limit][&body=1][&lang=en\|hu] Wiki proxy: fetches Grav's custom/pages.json via WIKI_GRAV_URL, so the frontend never talks to the wiki. lang picks the wiki language, defaulting to en
GET /api/rss/blog RSS of blog-tagged wiki pages
GET /api/rss/releases RSS of the latest releases
GET /api/download?path=… Logged download (records IP / UA / referer, then serves)
GET /api/swagger apipie docs
GET /file/*path Direct file download; release paths in API responses point here
POST /build/upload Artifact upload, one file per request; application token with the upload scope
POST /build/publish Release publishing; application token with the update scope, called by CI after upload

Tokens are described in the WarpEngine article.

The store registry (GET /api/stores) says which catalogs a client can install from and where each store's config lives. It is public, because the desktop client reads it on first run and has nobody to log in as. A row is three fields (name, catalog_url, store_repository_url), edited in ActiveAdmin ▸ 🛒 Stores. It lives in the host app, not in WarpEngine: the engine serves one catalog and does not know who ships stores for it.

Publish pipeline

/build/publish dispatches by platform to a Platforms service (tic80, love, ebitengine, c64, godot, bevy, phaser). Each one picks up the uploaded artifacts (C64: <name>-<version>.prg + <name>-<version>.metadata.json), upserts the Software from the metadata, adds a Source Code external link from its site field, and creates the Release. The Gitea + Woodpecker side is in the Deployment article.

Frontend

A Vue 3 SPA built with Vite in TypeScript: vue-router (one module per page), Pinia stores per domain (software, events, members, git, blog, howtos, youtube, ui), vue-i18n, and Tailwind CSS + TuiCSS for the retro terminal look. Traefik proxies it on the same base domain as the API.

Pages: home, catalog (index + show), blog, code, howtos, team, contact. The catalog show page has an image lightbox, the release list, download counts and web-playable releases.

One client module per source under src/api/:

Module Source
software.api.ts, event.api.ts, member.api.ts Catalog API
wiki.api.ts Catalog API wiki proxy (blog / howto tags), passing the interface language as lang. VITE_WIKI_BASE is only used to build external links to Grav
git.api.ts Gitea REST API v1 (token WEBAPP_GITEA_TOKEN) for the Code page
youtube.api.ts YouTube Data API: latest channel video and view count