Qurazy's new engine
Under the hood: Qurazy's new engine
What you see when you use Qurazy hasn't changed: write a question, share it, solve one. But over the past four months we rebuilt almost everything underneath it — from the version of the technology it runs on to the way it gets installed on a server. Here's what we did, with the jargon translated into plain language.
The short version, in numbers: since May, 1,264 files changed and roughly 75,000 lines of code were added. Nothing broke on your side of the screen.
Why rebuild the foundations at all?
From the outside, a web application is just the page on your screen. Underneath, dozens of ready-made building blocks are at work: the framework that draws the page, the component library that supplies the buttons and menus, the compiler that translates our code into something browsers understand, the tools that run the tests.
Those building blocks ship new versions constantly. Fall behind and two things happen: you stop receiving security patches, and every new feature gets a little harder to add. It's the plumbing in a building — the wallpaper still looks fine while the pipes quietly age. So we replaced the pipes.
Angular 22 and TypeScript 6
Qurazy runs on a framework called Angular. We moved from Angular 21 to 22, and upgraded TypeScript — the language we write the code in — to version 6. This isn't a one-command job: when the version changes, so do the rules across hundreds of files. A single upgrade step touched 208 of them.
The payoff reaches you directly: the new version packs the files you download into smaller bundles and draws the page with less work.
| Before | After |
|---|---|
| Angular 21 | Angular 22 |
| TypeScript 5 | TypeScript 6 |
| PrimeNG | Optimus UI |
| Karma + Chrome | Vitest |
Signals: updating only the part that changed
In the old model, whenever anything in the app changed, the framework asked "what on screen is different now?" and checked everything from top to bottom. The new approach — signals — flips that around: each piece of data knows which part of the screen depends on it, and when it changes, only that part is updated.
In practice that means less stutter in long lists and less pointless work for small, frequently changing elements like the notification counter. We moved our avatar, question card and form components onto this model.
In the same pass we retired the old way components asked for the services they need. Today 313 files use the modern inject() approach; only 4 still use the old one.
New template syntax: *ngIf is gone
In page templates we write conditions like "show this if the user is signed in." Angular has an old syntax for that (*ngIf, *ngFor) and a new one (@if, @for). The new syntax is easier to read, and it lets unused code be dropped from the bundle entirely.
The migration is complete: zero instances of the old syntax remain in the codebase.
We changed where the buttons come from
Buttons, dropdowns, dialogs — instead of writing these from scratch, we took them from a ready-made library: PrimeNG. We replaced that library with Optimus UI, an open-source, community-maintained alternative under the MIT license.
It was surgery across 88 files, and it landed without breaking anything visible. Light and dark theme support, along with Qurazy's orange identity, carried over untouched.
A folder layout where things are findable
The code had drifted into two competing ways of organizing itself. We split it into three clear layers:
- core — the foundations used everywhere: sessions, categories, notifications
- features — self-contained groups of pages: blog, profile, questions, explore
- libs — the shared pieces reused across the app: components, services, helpers
This is the kind of change you'll never see, but it sets the pace of every feature we add from here. When you report a bug, finding the file now takes seconds rather than minutes.
A safety net: code that checks itself
This is where we invested the most. An automated test is, in plain terms, code checking itself: you hand a function some sample data and a machine verifies it produces the right answer. If fixing one feature breaks another, the tests catch it before you ever notice.
We moved the test setup off the old browser-dependent tool and onto Vitest, which is far faster, and we wrote a lot more tests:
- 253 test files
- 1,790 individual test cases
Every change made to Qurazy from now on gets made with that net underneath it.
What we did about speed
Qurazy renders the page on the server first and sends it to you as ready-made HTML. That way content appears before the app has fully loaded, and search engines can read the page. During this period we improved:
- Pre-rendered pages: stable pages like sign-in, sign-up, about, help and privacy are prepared before anyone asks for them.
- No downloading the same data twice: the data the server used to render the page travels inside the HTML, so the browser doesn't repeat the request.
- Caching rules: things that don't change — images, fonts — are marked to be kept for a long time, while the page itself is always fetched fresh.
- Compression: every response leaving the server is compressed.
- A size budget: we set a 2.2 MB warning threshold for the initial download. Cross it and the build warns us, so bloat can't accumulate unnoticed.
- PWA: the app can be installed on your phone and opens much faster on repeat visits.
Deployment: the end of "it worked on my machine"
We also rebuilt how the app gets onto a server. Everything now ships as a Docker image, built in two stages: the first stage compiles the code, and only the files actually needed to run get copied into the second. The result is a small, plain runtime that carries no build tooling inside it.
The app also runs as a limited, dedicated user rather than as the server's administrator — a basic security measure that's skipped surprisingly often. And we pinned the exact Node.js version, so the code that runs on a developer's laptop runs identically in production.
Two languages, correct from the first frame
Qurazy is live in English and Turkish. We wrote a separate loader so the server can read the translation files too. What that means for you: the text is already in the right language the moment the page arrives — no more of that jarring flicker where the page shows one language and then switches.
Opening Qurazy up to the outside
Finally, we added a few standards so Qurazy content looks right beyond our own site:
llms.txt— a plain-language summary written so AI assistants correctly understand what Qurazy is and what each page does.- oEmbed and an embed script — you can embed a Qurazy question in your own site or blog.
- Sitemap and feeds — an XML sitemap covering questions, profiles and blog posts, plus RSS, Atom and JSON feeds.
Small fixes you can actually see
Among the big jobs, some small things got fixed too: the browser tab title that was accidentally showing a single letter now reads "Qurazy," the app manifest loads from the right address, and the theme inconsistencies on hover states are gone.
What's next
- Moving forms onto the new signal-based model, starting with sign-in and sign-up
- Turning on TypeScript's strictest checking mode in full — meaning errors get caught as the code is written, before they ever reach you
- Removing the last of the old module structure
If you run into something slow or strange while using Qurazy, tell us. The whole point of rebuilding the foundations is being able to turn that kind of feedback into a fixed version quickly.