RUEN
Start a project

Studio product · 2026

RussiaOnline.wiki

An encyclopedia of a game world: a reference with faceted filters, an interactive map, a plate registry, a desktop assistant and its own CMS.

views in the first month
143.7k
visitors
25.0k
of traffic from search
92%

Open the site — russiaonline.wiki ↗

RussiaOnline.wiki home page

An encyclopedia for the world of Russia Online, a roleplay project set in present-day Moscow. Not “another wiki” but a database with tools: typed attributes, faceted filters, a table mode, object comparison, an interactive map and a full CMS.

Today the site holds 790 articles, 170 map markers and 11 sections.

Three days to launch

The constraint was neither budget nor scope — it was a date. The game project was opening and the wiki had to work on opening day. Three days to the first working version. Everything below grew out of the architectural decisions taken in those three days, because there would be no time to redo them later.

One entity instead of ten tables

The decision that made three days possible. Instead of parallel tables for vehicles, items, jobs and the rest — a single Entry model with a kind field and a typed JSON attributes field.

Everything else follows: one search index for the whole site rather than ten different queries; one editor in the CMS instead of ten forms with duplicated logic; one revision history and one SEO layer. A new content type is added by describing a schema, not by migrating the database.

Whatever is actually filtered and sorted on is mirrored into indexed columns, so the database discards most rows before the application ever sees them.

One field description drives five parts of the interface

The attribute schema is the single source of truth. Describing a field defines, all at once: the form in the CMS, the info panel on the article, the faceted filter panel, the column in table mode and the “better” direction in comparison mode.

Mark a field filterable and it appears in the section’s filter panel by itself. Say that lower is better and comparison mode starts highlighting the best value in the row. There is no hand-written markup per type at all.

What analytics showed in the first month

Yandex Metrica summary: 143.7k page views, 48.7k sessions, 25.0k visitors

Yandex Metrica, 20 August – 25 September 2026: from launch to the moment of the screenshot.

143.7 thousand page views, 48.7 thousand sessions, 25 thousand visitors in a little over a month. Average time on site 2 minutes 58 seconds, 2.95 pages per session, 13.8% bounce rate.

The important part is not the total but its composition: 131.9 thousand of those 143.7 came from search engines. That is 92%. Direct visits accounted for 8,113, referral links for 1,232, social networks for 269.

That is what a reference site looks like when search engines find it useful: server rendering, a precomputed index, markup and URL structure designed in from day one rather than bolted on later.

The design, the icons and the content are ours

The project arrived without mockups. The design system, palette, typography, icons and content were made entirely by us.

The palette is derived from the game project’s own brand: warm graphite instead of pure black, a warm off-white instead of white, the brand red as the accent. Both themes, dark and light, are described in tokens — no component knows a specific colour value.

Typography is three families with distinct jobs: a display face with full Cyrillic, an interface face, and a monospace for numeric data. All self-hosted, with no external requests and no layout shift.

On top of that: 47 three-dimensional section icons drawn for the project, and thousands of article images normalised to a single look.

The interactive map

A map of Moscow on Leaflet in a flat coordinate system — game-world coordinates rather than latitude and longitude. 170 markers across categories, filters and search, and state kept in the URL, so a link to a particular view can be shared.

The plate registry

A registry of in-game vehicle plates. A person uploads a screenshot and states which plate is on it; the service checks whether that string occurs in the recognised text.

The problem is posed backwards from the usual one. Finding “some plate” in a photograph is hard: you have to locate the region, correct the perspective, tell a plate from a shop sign. None of that is needed here — the plate has already been named, so it is a substring comparison.

Two decisions that took real work:

  • Normalisation. The format is taken from our own article about in-game plates, not from general knowledge of Russian plates. People type a plate however it comes out: Latin lookalikes, lowercase, spaces, dashes. Only the canonical form goes into the index — otherwise search finds nothing and the service looks broken while the code is perfectly fine.
  • “Almost” is a separate verdict, not a flavour of “found”. Real screenshots showed that when recognition fails, it fails on exactly one character. Discarding those silently throws away most of the value of the check. And a false “found” lulls the moderator: they learn to trust the badge and one day wave a forgery through.

The desktop assistant

A desktop application for the project’s state structures: find an article of law by number, see the offence and the sanction, copy the wording. 5,680 articles across 82 laws on three servers, plus repealed ones marked as no longer in force.

Two decisions that shape its whole behaviour:

  • The server is part of the query. The same article number means different offences and different sanctions on different servers of the project. So the server selector sits in the header, is always visible, and is remembered between runs.
  • A stale reference says so. On start the assistant fetches a fresh parse of the laws from the site. With no network it opens the last saved copy and says so in the header. A penalties reference passing itself off as current is worse than none.

The assistant does not touch the game and types nothing into it — it is a separate window, and the wording is pasted by a person.

Content arrives on its own

Project news is handled by a polling service: it pulls posts from the channel, classifies them and publishes them into the wiki’s updates feed. Editing works straight from chat through a separate bot with its own service.

Polling was chosen over a webhook deliberately: a webhook requires Telegram to reach our address — a dedicated route, a secret, and a dependency on whether the app is up and the certificate is valid. Long polling holds one outbound connection and depends on nothing but the network.

How it runs on the server

nginx with TLS, compression and rate limiting; the application under systemd as a dedicated system user with no login, NoNewPrivileges and ProtectSystem.

Deployment is automatic: push to the main branch, checks in CI, and the server pulls the code with its own read key. The deploy key held by GitHub is constrained on the server side: sshd runs only the deploy wrapper and ignores whatever the client asks for. A leaked key grants no shell, no file copying and no port forwarding — only the same deploy that already runs on every push.

TypeScript · Next.js 16 · React 19 · Prisma 7 · SQLite · Tailwind CSS 4 · Leaflet · TipTap · Tesseract · Electron · Python · nginx · systemd