Skip to content

HISTORY Wiki

The player wiki of HISTORY, a Metin2 private server: 1,600+ items, monsters, maps, quests and skills in 13 languages, edited in place by its admin.

Recommended
Client
HISTORY Metin2 server
My role
Full-stack engineer & DevOps specialist
Type
Wiki and CMS
Timeline
Jun 2025 – present
Built with
  • JavaScript
  • Next.js
  • next-intl
  • Material UI
  • styled-components
  • Node.js
  • MongoDB
  • Mongoose
  • Cloudflare
  • Nginx
  • Coolify
  • Telegram
  • Git
  • GitHub

Screens15 screens

Screen 1 of 15

The home page, in 13 languagesDesktop · ⁦1 / 15⁩

Select the centre screen to see it full size.

Overview

HISTORY is an old-school Metin2 private server, and its wiki is where players look things up: every weapon and armour with its +0 to +9 upgrade ladder, every monster with its drops and spawn maps, the quests, the dungeons and the skills of all five classes.

I built the wiki and the mini CMS behind it, and I still maintain both. Metin2 wikis are dense in-game panels rather than articles, so every page recreates a panel from the game, and the server's admin edits those same pages in place instead of filling in forms. The wiki serves 1,622 entries in 91 categories, in 13 languages, Arabic included, right to left.

What I delivered

  • Wiki pages that recreate the game's own panels: items, monsters, maps, quests, NPCs and skills
  • Weapon, armour and jewellery tables with the full +0 to +9 upgrade ladder and upgrade costs
  • A mini CMS that edits every page in place, with the same components the visitors see
  • A rich-text editor (Tiptap) with tables, column grids, colours and sized images
  • 13 languages with a translated URL per page, Arabic right to left
  • An instant header search across every item, monster, map and skill, with typo tolerance
  • Class skill sections: 5 classes, 63 skills, with animated previews on a CDN
  • Every picture that stands for a page links to it, across 3,000+ images
  • Fully cached pages, refreshed the moment an admin saves
  • Category trees, ordering by drag and drop, and a home-page editor
  • One-click backup sent to Telegram, and page errors reported to Telegram

How I built it

One component, two modes

There is no separate admin form. Every layout takes an editing flag and swaps inputs in for text, so the server's admin edits the exact page players read, in place, and a save is checked against that layout's schema before it reaches the database. Twelve layouts cover the whole wiki. When the client asks for something new, the default answer is a per-category option rather than a new layout, so a change reaches only the categories that asked for it.

Pages that render once, then come from cache

Profiling the slowest page showed the database at 0.8% of the time. The real cost was React rendering and styling: one page serialised 11,444 style objects, and only 40 of them were distinct. I moved those styles out of the per-item loops and made every public page fully cached rendered output, with no time limit and purged by tag the moment an admin saves.

Measured on 33 routes Before After
Total server time 22,030 ms 1,804 ms (−92%)
Slowest pages 1.3–3.1 s 51–165 ms (18–29× faster)
Bytes over the wire 180–459 KB 54–99 KB (−70 to −78%)

I checked that nothing visible changed: 31 of the 33 pages came out identical, word for word and link for link, and the other two changed on purpose.

13 languages without 13 copies

Content is written once in Romanian. Each document carries sparse translations of its text and links only, merged at read time (the reader's language, then English, then Romanian), so images, numbers and structure are never duplicated. Every page has its own URL per language. A link in any language redirects to the right one, and pages declare all 13 alternates for search engines.

The translation pipeline turns 30,937 strings into 6,127 units by lifting out links and numbers, so translators never touch a URL, and output whose tags or placeholders don't match is rejected. About 45% of the units come straight from the game's official name tables. Machine-translation-service output is refused outright: once, it had slipped into 3,152 units.

A search that answers in milliseconds

The browser downloads its language's whole index once, about 1,700 entries in roughly 60 KB gzipped, and searches it in memory on every keystroke. Matching ignores accents and tolerates a typo, results are grouped by kind, and an entry with no page of its own lands on its card on the category page.

Rich text that survives the editor

Descriptions moved from Markdown to sanitised HTML edited in Tiptap, with resizable tables, column grids, colours and images sized from the image itself. Scripts migrated the old content, backfilled image sizes and proved the stored HTML round-trips through the editor unchanged.

Every picture is a link

An image links to its page when an anchor sits right next to it in the text, or through a stored link on list entries. 2,340 of the 3,249 images in rich text became links. The anchors generate no box of their own, and I confirmed the rendered pages stayed byte-identical apart from the new links.

Skills, on a CDN

Five classes, nine skill trees and 63 skills got their own in-game skill panel. Their 483 images and animations (91 MB of GIFs) live on Bunny.net and load only when scrolled into view.

Running it

Coolify deploys the app. A one-click backup downloads every item and category as JSON and sends the same file to Telegram, and a crash on an item page reports its stack trace there too.

By the numbers

Entries 1,622 items in 91 categories
Languages 13, Arabic right to left
Translated strings 30,937, in 6,127 units
Layouts 12
Server time, 33 routes 22.0 s → 1.8 s
Linked images in rich text 2,340
Commits 279

Next project

The seal of the Church and Monastery of the Virgin Mary, Maadi: three domes with crosses above the Nile

St Mary Maadi

Institutional platform · 2025

One platform for St. Mary Church in Maadi that runs its hotel bookings, Nile trips, sports tournaments, and liturgy and event bookings.

Have a project like this one?

A few lines are enough: what you need, and roughly when.

Start a project