Skip to content
megapromotingLet's talk

Expertise · Websites

This site is our technical specification — including the measurements that do not favour us.

We build server-rendered sites, with images in AVIF and WebP, security headers checked from the outside, a sitemap generated from data and an acceptance check run after each publication. All of this can be inspected on the page you are reading.

Already builtWe cannot cite a client site without their consent, but we do not need to: the proof is this page itself. It runs Next.js 16.2.4 with React 19.1.0, is served prerendered from cache (`x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`), carries HSTS with `preload`, `nosniff`, `SAMEORIGIN`, `Referrer-Policy` and a complete content policy — verified with `curl -I` on 06.09.2026. The sitemap contains 147 addresses, all generated from data, not handwritten. The second implementation, in the same repository: the form infrastructure — append-only journal, public health probe, rate limiting — and the acceptance script run after publication.

A showcase site has only one honest test: can you verify from the outside what the company says about it? That is why this page does not list technologies, but things you can control yourself with a command. The site runs Next.js 16.2.4 and React 19.1.0, and the pages are prerendered at build time and served from cache — you can see it in the response headers: `x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`, `s-maxage=31536000`, with a 300-second window in which an old page may still be served while it refreshes.

Server-side rendering is not an architecture preference. A visitor with a weak connection and a search engine receive the same complete HTML, without waiting for JavaScript. On top of that comes resource discipline: images are output in AVIF and WebP, with a one-year cache; fonts are hosted by us, not requested from an external service; eight interface libraries have optimised imports so they do not pull entire modules for a single icon.

The security headers are sent from two places and checked in the actual response, not only in configuration: secure transport enforced for two years with subdomains and preload list enrolment, file type sniffing blocked, framing restricted, referrer policy, and a permissions policy that closes the camera and leaves the microphone only for the same origin — because voice demonstrations need it and, without that exception, the browser refuses silently.

The last part is the one that sets us apart, and it is unpleasant: we also publish what we measured badly about ourselves. The server still does not offer Brotli or HTTP/2. The translation catalogue is sent on every navigation and costs about 70 KB compressed each time. A 443 KB bundle contains four language catalogues, of which only one is routable. The fonts also bring the Cyrillic subset, although the checked pages contain no Cyrillic character. These figures are measured, written in the repository and in the repair list. A provider that does not have such figures about its own site either has not measured, or does not want to say.

What it covers

The work, by component

Server-side rendering, served from cache

The pages are prerendered at build time and delivered as complete HTML, not built in the browser. In the real response, `x-nextjs-prerender: 1` and `x-nextjs-cache: HIT` appear, with `cache-control: s-maxage=31536000` and a 300-second window in which the old version may still be served while it is refreshed. The practical effect: a visitor with a weak connection and a crawler receive the same content, in the same request.

Images and fonts on budget, not on luck

The configured formats are AVIF and WebP, with a minimum cache duration of 31,536,000 seconds — one year — and an `immutable` header on static files, images and fonts. Fonts are hosted by us at build time, not requested from an external service on every visit, and are displayed with `swap`, so the text appears before the font is downloaded. There is also a batch compression script, with quality 80 for WebP and 75 for AVIF, so the source does not depend on what someone exported from the graphics editor.

Security headers sent from two places and checked in the response

From the application: enforced secure transport for 63,072,000 seconds with subdomains and preload list registration, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin` and a permissions policy that turns off the camera, allows the microphone only for the own origin and disables interest grouping. From the web server, separately: a complete content security policy, with the explicit list of allowed origins. At handover, it is stated explicitly that there are two places — otherwise the next person who changes something will look in the wrong one.

The site map generated from data, not written by hand

The site map is built from five sources — 13 fixed addresses, the articles, 19 products, 12 services and 100 service × domain combinations — and goes through a final deduplication. The result: 147 addresses, counted both in code and in the file served in production. A new page is added automatically; a deleted one disappears. No one maintains a parallel list that goes out of sync in three weeks.

Old addresses do not die: 43 permanent redirects

A structural clean-up leaves behind addresses that someone has bookmarked or published. In the configuration there are 43 permanent redirects — 9 guides to the blog, 20 orphaned articles, 6 case studies remapped and 8 individual pages. There are also 11 pages that redirect from within the application; they are functionally correct, but more expensive than a configuration rule, and are listed as such in the fixes list.

The form is infrastructure, not decoration

The request is written to an append-only log before delivery is attempted, with a second line for the result; there is a public health probe that says whether a lead can reach a human right now; and requests to interfaces are limited to 10 per minute, with the key taken from the last hop of the forwarded address header, not the first — the first is sent by the client. The reasons are written in code, not in separate documentation.

Acceptance check after every publication

A script opens each product page, in groups of three, and fails if the 200 code is missing, the questions anchor is missing, the example anchor is missing or the canonical address is missing. It then checks the site map — that it contains every product and does not contain language variants that cannot be opened — and `robots.txt`, so it does not block the resources needed for rendering. Each check corresponds to something that has already broken once.

Canonical address resolved once, for the whole site

The canonical address is declared relative, in a single place in the base layout, and is resolved for each route separately. The same solution for the social sharing address, which previously declared the home page on most pages. It is a line of code that replaces a convention each new page would have had to remember on its own — and which, inevitably, it does not remember.

What does not work is written in the repository, next to the code

The repository contains a file of known issues that explains, for example, why the language variants in the address do not switch the language, why the obvious solution makes things worse — on server rendering there is neither local storage nor browser, so the detector falls back to English and all pages come out in English — and what the two real solutions are. We prefer a technical buyer to find the limitation written by us, not discovered by them.

What it looks like

The path, step by step.

01

The inventory of addresses and what happens to the old ones

The first delivery is the list of existing addresses and the decision for each: remains, redirects, or disappears. On this site, that resulted in 43 permanent redirects. It is the work everyone skips and that, a few months later, produces error pages in search results.

02

The content structure and the sources from which it is generated

Product and service pages are built from data, not from separate files. From here come the automatically generated sitemap, the consistent canonical addresses, and the ability to verify programmatically that each page has what it needs. We deliver the data structure, not just the pages rendered from it.

03

The build, with budgets set before content

We set from the outset what format the images have, what is cached and how much, what is rendered on the server and what remains interactive in the browser. The content is then placed within this budget. The reverse order produces sites that look good at launch and become heavier with each added page.

04

Publication with a gate and acceptance check

Publication checks the server's free memory, runs the dependency security audit, builds from a clean state, and confirms that the process is started before reporting success. Immediately afterwards, the acceptance script opens the pages and checks anchors, canonical addresses, the sitemap and `robots.txt`. Both are handed over, not kept by us.

05

Handover, with the list of gaps and measurements

We hand over the code, the publication procedure, the rollback procedure, the health addresses — and the written list of what is not covered, with figures. For this site, the list includes the lack of Brotli and HTTP/2 on the server, the cost of the translation catalogue on each navigation, and the unused subset of fonts. We prefer the list to come from us.

Four layers verifiable from the outside1Pre-rendered HTML served from cache2AVIF/WebP images and locally hosted fonts3security headers from the application and the web server4the sitemap and canonical addresses generated from the data
Four layers verifiable from the outside

The data

What we touch, where it lives, and how long it stays

The questions anyone with a data protection officer would ask — asked here before they do.

The data from the contact form
Name, email address, phone, company, selected service, message, source page and the visitor's network prefix. They are written to a log on the company's own server, with `0700` rights on the directory and `0600` on the files, outside the version directory. Term: 24 months, applied by code at each write, not by a scheduler that can be forgotten.
IP address, cut before being written
Only the network prefix is kept — `/24` for IPv4, `/48` for IPv6 — and the last hop is read from the header, because the first is sent by the client and proves nothing. The same function is also used by rate limiting, so there is no second place where the full address could accidentally end up.
Traffic statistics
Measurement passes through the configured analytics tool and is activated after consent. The real cookies were verified empirically on the live site, before and after acceptance, and the cookie policy was rewritten after that verification — not the other way round. The previous policy listed cookies that did not exist.
The processing register, versioned alongside the code
Each type of data touched by the site has an entry with purpose, legal basis, categories and term, in a document kept in the same repository. When the code changes a term, the document changes in the same commit. What is not established — for example, the actual retention in the analytics account — is explicitly marked as a point to be clarified, not stated as fact.
What does not leave the server
Notification tokens, vendor keys and channel identifiers. The health probe returns only logical values, precisely so it can be queried by an external service without disclosing anything about the configuration.

A case

What the audit of its own site shows when you publish it in full

The situation

After a restructuring, the site itself seemed fine: all pages returned 200, the dashboard was green. We asked the question we ask clients: what does an external measurement, made across all addresses at once, not just on the homepage, say?

What we built

We went through every known address with direct requests — 249 addresses, 23 columns per address, no redirect following, with at most six requests in parallel — and put the result into a versioned tabular file. On top of it we ran separate checks: the actual compression of HTML, what is transmitted on each navigation, what the JavaScript packages contain, which fonts are downloaded, what cache and transport headers the server offers. Every figure was verified in the real response, not inferred from the configuration.

What came out

244 addresses return 200 and 5 redirect. 131 pages had no canonical address, and 219 out of 244 declared the homepage as the share address — both are now fixed with one line each in the base layout, which applies to every route. The server does not offer Brotli or HTTP/2. The translation catalogue, 2.268 keys, is transmitted on every navigation and costs approximately 70 KB compressed each time. A 443 KB package contains four language catalogues, of which only one is routable. The fonts also bring the Cyrillic subset, although the pages checked contain no Cyrillic character. All figures, with the commands that reproduce them, are written in the repository.

What the case does not say

These are laboratory measurements, made from the outside, with direct requests. They are not field data from real visitors and we do not present them as such: perceived loading metrics could not be read in the tool used and are explicitly marked as unmeasured. We did not run the application build during the audit, because several people were working on the same checkout.

Questions

What people ask us before they call

What do you build with, concretely?

Next.js 16.2.4 with React 19.1.0 and TypeScript, with Tailwind for styles and accessible interface components based on Radix primitives. The pages are pre-rendered at build time and served from cache — this is verified from the outside: the response headers contain `x-nextjs-prerender: 1` and `x-nextjs-cache: HIT`. It is not a list of technologies we read; it is the stack on which the page you are reading now runs.

How do I check for myself what you say about security?

With a single command: `curl -I https://www.megapromoting.com/servicii`. You will see `strict-transport-security: max-age=63072000; includeSubDomains; preload`, `x-content-type-options: nosniff`, `x-frame-options: SAMEORIGIN`, `referrer-policy: strict-origin-when-cross-origin`, a permissions policy that closes the camera and leaves the microphone only for its own origin, plus a content security policy with the explicit list of origins. The first five come from the application configuration; the last is sent by the web server — two different places, and we state that in the handover.

How do you know you did not break something in the last release?

From an acceptance script run after release. It opens each product page and fails if the 200 code is missing, the questions anchor, the example anchor or the canonical address; it then checks that the sitemap contains each product and does not contain language variants that do not open, and that `robots.txt` does not block rendering resources. Each check in the list corresponds to something that has already broken. The script is handed over with the project — you can run it too.

Is your site fast?

It depends what you measure, and we have figures in both directions. Good: the pages are pre-rendered and served from cache, images come out in AVIF and WebP with one-year cache, fonts are hosted locally. Bad, measured on the site itself: the server does not offer Brotli or HTTP/2 — a request with `Accept-Encoding: br` gets an uncompressed response; the translation catalogue is transmitted on every navigation and costs approximately 70 KB compressed each time; a 443 KB package contains four language catalogues of which only one is routable. I am not giving you a laboratory score; I am giving you the measured octets and the list of fixes that comes out of them.

Who maintains the sitemap?

Nobody, and that is the correct answer. It is generated from five data sources — fixed addresses, articles, products, services and service × domain combinations — and goes through a final deduplication. It comes out as 147 addresses, the same figure in the code and in the file served in production. A new page gets in automatically. What is missing today, to say it plainly: the entries do not carry a last modified date, and 93 indexable addresses are not yet in the map. They are in the repair list, not hidden.

Do you make multilingual sites?

Here I need to be precise, because this is the clearest limitation of this site. Language switching from the address does not work: the configuration fixes Romanian, so the detector never reads the parameter. I have written in the repository why the obvious solution is worse — with server-side rendering there is neither local storage nor a browser, so the detector falls back to English and all pages come out in English — and what the two real solutions are: path-based routes, with a language segment, or resolving the language on the server on each page. The first is recommended. For a new project we start directly with path-based routes; for an existing one, it is work, not a setting.

What happens to old addresses when you rebuild a site?

They are inventoried and each gets a decision: it stays, it is permanently redirected, or it disappears. The clean-up of this site resulted in 43 redirects in the configuration. There are also 11 pages that redirect from within the application — they work, but they build the page before sending the redirect response, which is wasteful; they are on the list to be moved into the configuration. I am telling you this so you know what kind of list you receive at handover.

How do I know the form really sends it?

You ask it: `GET /api/health/contact` returns 200 if a lead can reach a person now and 503 if not, separately checking that the notification channel token is valid and that the request log can be written. The response contains only logical values, never the token. It exists because this is exactly where things broke once: the token was revoked, the route returned 500, requests were lost without a trace. Now the request is written to the log before delivery is attempted.

What do you not do?

We do not promise search rankings, conversion rates or performance scores that we have not measured on your project. We do not deliver a site without a list of old addresses and without a rollback procedure. We do not take responsibility for third-party platforms to which we do not have access. And we do not present as ready something that has a known limitation — if I have a limitation, you will find it written in the repository before you find it in production.

What the statements above rest on (15 sources)
  1. Production serves prerendered pages from cache: `x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`, `cache-control: s-maxage=31536000`, `x-nextjs-stale-time: 300`https://www.megapromoting.com/servicii · 2026-09-06
  2. Security headers in the real response: HSTS `max-age=63072000; includeSubDomains; preload`, `nosniff`, `SAMEORIGIN`, `strict-origin-when-cross-origin`, permissions policy with `microphone=(self)`; plus a full content security policy served by nginx and ABSENT from `next.config.ts`https://www.megapromoting.com/servicii · 2026-09-06

13 of them are code and files from our repositories. We don't publish their name or line: together, on a single page, they would describe too precisely how systems that aren't only ours are built. We go through them with you, in the repository, on request — verification stays possible, it just happens in a conversation.

What would you want to work better?

Tell us about your process. Together we decide what is worth building, what we can connect, and how we check the result.

Let's talk