Przejdź do treści
megapromotingPorozmawiajmy

Ekspertyza · Strony internetowe

Ta strona internetowa to nasza specyfikacja techniczna — włącznie z pomiarami, które nie są dla nas korzystne.

Budujemy strony renderowane po stronie serwera, z obrazami w AVIF i WebP, nagłówkami bezpieczeństwa zweryfikowanymi z zewnątrz, mapą witryny generowaną z danych i testem akceptacyjnym uruchamianym po każdej publikacji. Wszystko można sprawdzić na stronie, którą czytasz.

Już zbudowaneNu putem cita un site de client fără acordul lui, dar nu avem nevoie: dovada e chiar pagina asta. Rulează Next.js 16.2.4 cu React 19.1.0, e servită prerandat din cache (`x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`), poartă HSTS cu `preload`, `nosniff`, `SAMEORIGIN`, `Referrer-Policy` și o politică de conținut completă — verificate cu `curl -I` pe 06.09.2026. Harta de site conține 147 de adrese, toate generate din date, nu scrise de mână. A doua implementare, în același depozit: infrastructura formularului — jurnal append-only, sondă publică de sănătate, limitare de rată — și scriptul de acceptare rulat după publicare.

Strona prezentacyjna ma jeden uczciwy test: czy można z zewnątrz zweryfikować to, co firma o niej mówi? Dlatego ta strona nie wymienia technologii, lecz rzeczy, które można samodzielnie sprawdzić jednym poleceniem. Strona działa na Next.js 16.2.4 i React 19.1.0, a strony są prerenderowane podczas budowania i serwowane z cache — widać to w nagłówkach odpowiedzi: `x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`, `s-maxage=31536000`, z oknem 300 sekund, w którym stara strona może być jeszcze serwowana podczas odświeżania.

Renderowanie po stronie serwera nie jest preferencją architektury. Odwiedzająca lub odwiedzający z słabym połączeniem i wyszukiwarka otrzymują ten sam pełny HTML, bez czekania na JavaScript. Do tego dochodzi dyscyplina zasobów: obrazy wychodzą w AVIF i WebP, z rocznym cache; czcionki są hostowane przez nas, a nie pobierane z zewnętrznej usługi; osiem bibliotek interfejsu ma zoptymalizowane importy, żeby nie wciągać całych modułów dla jednej ikony.

Nagłówki bezpieczeństwa są wysyłane z dwóch miejsc i sprawdzane w rzeczywistej odpowiedzi, nie tylko w konfiguracji: wymuszony bezpieczny transport przez dwa lata z subdomenami i wpisem na listę preload, zakaz zgadywania typu pliku, ograniczenie osadzania w obcych ramach, polityka odsyłacza oraz polityka uprawnień, która zamyka kamerę i zostawia mikrofon tylko dla własnego źródła — bo demonstracje głosowe tego potrzebują i bez tego wyjątku przeglądarka odmawia po cichu.

Ostatnia część jest tym, co nas wyróżnia, i jest nieprzyjemna: publikujemy też to, co zmierzyliśmy u siebie źle. Serwer nadal nie oferuje Brotli ani HTTP/2. Katalog tłumaczeń jest przesyłany przy każdym przejściu i kosztuje za każdym razem około 70 KB po kompresji. Pakiet 443 KB zawiera cztery katalogi językowe, z których tylko jeden jest routowalny. Czcionki dostarczają też podzbiór cyrylicy, mimo że sprawdzone strony nie zawierają żadnego znaku cyrylickiego. Te liczby są zmierzone, zapisane w repozytorium i na liście poprawek. Dostawca, który nie ma takich liczb o własnej stronie, albo nie mierzył, albo nie chce powiedzieć.

Co obejmuje

Praca, komponent po komponencie

Renderowanie po stronie serwera, podawane z cache

Strony są prerenderowane przy budowie i dostarczane jako pełny HTML, a nie budowane w przeglądarce. W rzeczywistej odpowiedzi pojawiają się `x-nextjs-prerender: 1` i `x-nextjs-cache: HIT`, z `cache-control: s-maxage=31536000` i oknem 300 sekund, w którym stara wersja może być jeszcze podawana podczas odświeżania. Praktyczny efekt: odwiedzająca lub odwiedzający z słabym połączeniem i crawler dostają tę samą treść, w tym samym żądaniu.

Obrazy i czcionki z budżetem, nie ze szczęściem

Skonfigurowane formaty to AVIF i WebP, z minimalnym czasem cache 31.536.000 sekund — jednym rokiem — oraz nagłówkiem `immutable` dla plików statycznych, obrazów i czcionek. Czcionki są hostowane przez nas podczas budowy, a nie pobierane z zewnętrznej usługi przy każdej wizycie, i są wyświetlane z `swap`, aby tekst pojawił się przed pobraniem czcionki. Istnieje też wsadowy skrypt kompresji, z jakością 80 dla WebP i 75 dla AVIF, aby źródło nie zależało od tego, co ktoś wyeksportował z edytora graficznego.

Nagłówki bezpieczeństwa wysyłane z dwóch miejsc i sprawdzane w odpowiedzi

Z aplikacji: wymuszony bezpieczny transport przez 63.072.000 sekund z subdomenami i wpisem na listę preload, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin` oraz polityka uprawnień, która zamyka kamerę, zostawia mikrofon tylko dla własnego źródła i wyłącza grupowanie według zainteresowań. Z serwera WWW, osobno: pełna polityka bezpieczeństwa treści z jawnie podaną listą dozwolonych źródeł. Przy przekazaniu zapisuje się wprost, że są dwa miejsca — inaczej następna osoba, która coś zmieni, będzie szukać w złym miejscu.

Mapa witryny generowana z danych, nie pisana ręcznie

Mapa witryny jest budowana z pięciu źródeł — 13 stałych adresów, artykułów, 19 produktów, 12 usług i 100 kombinacji usługa × domena — a następnie przechodzi końcową deduplikację. Wynik: 147 adresów, liczonych zarówno w kodzie, jak i w pliku serwowanym na produkcji. Nowa strona trafia tam automatycznie; usunięta znika. Nikt nie utrzymuje równoległej listy, która rozjeżdża się w trzy tygodnie.

Stare adresy nie umierają: 43 przekierowania stałe

Porządkowanie struktury zostawia po sobie adresy, które ktoś ma zapisane albo opublikowane. W konfiguracji są 43 przekierowania stałe — 9 przewodników do bloga, 20 osieroconych artykułów, 6 przemapowanych studiów przypadku i 8 pojedynczych stron. Jest też 11 stron, które przekierowują z wnętrza aplikacji; są poprawne funkcjonalnie, ale droższe niż reguła konfiguracyjna, i są tak opisane na liście poprawek.

Formularz to infrastruktura, nie dekoracja

Zgłoszenie jest zapisywane w dzienniku append-only przed próbą dostarczenia, z drugą linią dla wyniku; istnieje publiczna sonda stanu, która mówi, czy lead może teraz trafić do człowieka; a żądania do interfejsów są ograniczone do 10 na minutę, z kluczem pobieranym z ostatniego hopy nagłówka adresów przekierowanych, nie z pierwszego — pierwsze wysyła klient. Powody są zapisane w kodzie, nie w osobnej dokumentacji.

Kontrola akceptacyjna po każdej publikacji

Skrypt otwiera każdą stronę produktu, w grupach po trzy, i kończy się niepowodzeniem, jeśli brakuje kodu 200, kotwicy pytań, kotwicy przykładu lub adresu kanonicznego. Następnie sprawdza mapę witryny — czy zawiera każdy produkt i nie zawiera wariantów językowych, których nie da się otworzyć — oraz `robots.txt`, żeby nie blokował zasobów potrzebnych do renderowania. Każda kontrola odpowiada czemuś, co już raz się zepsuło.

Adres kanoniczny rozstrzygany raz, dla całej witryny

Adres kanoniczny jest deklarowany względnie, w jednym miejscu w układzie bazowym, i rozwiązywany osobno dla każdej trasy. To samo rozwiązanie dotyczy adresu udostępniania społecznościowego, który wcześniej deklarował stronę główną na większości stron. To jedna linia kodu, która zastępuje konwencję, którą każda nowa strona musiałaby pamiętać sama — i której, nieuchronnie, nie pamięta.

To, co nie działa, jest zapisane w repozytorium, obok kodu

Repozytorium zawiera plik znanych defektów, który wyjaśnia, na przykład, dlaczego warianty językowe w adresie nie przełączają języka, dlaczego oczywiste rozwiązanie pogarsza sytuację — przy renderowaniu po stronie serwera nie ma ani local storage, ani przeglądarki, więc detektor wybiera angielski i wszystkie strony wychodzą po angielsku — oraz jakie są dwa rzeczywiste rozwiązania. Wolimy, aby kupujący techniczny znalazł granicę napisaną przez nas, a nie odkrytą przez siebie.

Jak to wygląda

Trasa, krok po kroku.

01

Inwentaryzacja adresów i to, co dzieje się ze starymi

Pierwsza dostawa to lista istniejących adresów i decyzja dla każdego z nich: pozostaje, przekierowuje się albo znika. W przypadku tej strony wyszły 43 trwałe przekierowania. To praca, którą wszyscy omijają, a która po kilku miesiącach powoduje strony błędów w wynikach wyszukiwania.

02

Struktura treści i źródła, z których jest generowana

Strony produktu i usługi są budowane z danych, a nie z osobnych plików. Stąd bierze się automatycznie generowana mapa witryny, spójne adresy kanoniczne i możliwość programowej weryfikacji, że każda strona ma to, co trzeba. Dostarczamy strukturę danych, nie tylko strony renderowane z niej.

03

Budowa z budżetami ustalonymi przed treścią

Od początku ustalamy, w jakim formacie są obrazy, co i jak długo jest cache’owane, co jest renderowane na serwerze, a co pozostaje interaktywne w przeglądarce. Treść jest potem układana w ten budżet. Odwrotna kolejność produkuje strony, które wyglądają dobrze przy uruchomieniu i stają się cięższe z każdą dodaną stroną.

04

Publikacja z bramką i weryfikacją akceptacyjną

Publikacja sprawdza wolną pamięć serwera, uruchamia audyt bezpieczeństwa zależności, buduje z czystego stanu i potwierdza, że proces jest uruchomiony, zanim zgłosi sukces. Zaraz potem skrypt akceptacyjny otwiera strony i sprawdza kotwice, adresy kanoniczne, mapę witryny i `robots.txt`. Oba są przekazywane, nie zatrzymywane u nas.

05

Przekazanie z listą braków i pomiarów

Przekazujemy kod, procedurę publikacji, procedurę powrotu, adresy zdrowia — oraz pisemną listę tego, co nie jest objęte, z liczbami. W przypadku tej strony lista obejmuje brak Brotli i HTTP/2 na serwerze, koszt katalogu tłumaczeń przy każdej nawigacji oraz niewykorzystany podzbiór czcionek. Wolimy, aby lista pochodziła od nas.

Patru straturi verificabile din exterior1HTML prerandat servit din cache2imagini AVIF/WebP și fonturi găzduite local3antete de securitate din aplicație și din serverul web4harta de site și adresele canonice generate din date
Patru straturi verificabile din exterior

Dane

Czego dotykamy, gdzie to leży i jak długo zostaje

Pytania, które zadaje każdy, kto ma inspektora ochrony danych — postawione tutaj, zanim on je zada.

Dane z formularza kontaktowego
Imię, adres e-mail, telefon, firma, wybrana usługa, wiadomość, strona źródłowa i prefiks sieciowy odwiedzającej osoby. Są zapisywane w dzienniku na własnym serwerze, z uprawnieniami `0700` dla katalogu i `0600` dla plików, poza katalogiem wersji. Termin: 24 miesiące, stosowany przez kod przy każdym zapisie, a nie przez harmonogram, o którym można zapomnieć.
Adres IP, obcięty przed zapisaniem
Przechowywany jest tylko prefiks sieciowy — `/24` dla IPv4, `/48` dla IPv6 — i odczytywany jest ostatni hop z nagłówka, ponieważ pierwszy jest wysyłany przez klienta i niczego nie dowodzi. Ta sama funkcja jest używana także przez ograniczanie liczby żądań, więc nie istnieje drugie miejsce, do którego pełny adres mógłby trafić przez pomyłkę.
Statystyki ruchu
Pomiar przechodzi przez skonfigurowane narzędzie analityczne i aktywuje się po wyrażeniu zgody. Rzeczywiste pliki cookie zostały empirycznie sprawdzone na działającej stronie, przed i po akceptacji, a polityka plików cookie została przepisana po tej weryfikacji — nie odwrotnie. Poprzednia polityka wymieniała pliki cookie, które nie istniały.
Rejestr przetwarzania, wersjonowany obok kodu
Każdy typ danych dotknięty przez witrynę ma wpis z celem, podstawą, kategoriami i okresem, w dokumencie trzymanym w tym samym repozytorium. Gdy kod zmienia termin, dokument zmienia się w tym samym commicie. To, co nie jest ustalone — na przykład rzeczywista retencja z konta analitycznego — jest wyraźnie oznaczone jako element do doprecyzowania, a nie przedstawione jako fakt.
Co nie wychodzi z serwera
Tokeny powiadomień, klucze dostawców i identyfikatory kanałów. Sonda zdrowia zwraca wyłącznie wartości logiczne, właśnie po to, by mogła być odpytywana przez usługę zewnętrzną bez ujawniania czegokolwiek o konfiguracji.

Przykład

Co pokazuje audyt własnej strony, gdy publikujesz ją w całości

Sytuacja

Po restrukturyzacji własna strona wyglądała dobrze: wszystkie strony odpowiadały 200, pulpit był zielony. Zadałyśmy sobie pytanie, które zadajemy klientom: co mówi pomiar wykonany z zewnątrz, dla wszystkich adresów naraz, a nie na stronie głównej?

Co zbudowaliśmy

Przeszłyśmy bezpośrednimi żądaniami przez każdy znany adres — 249 adresów, 23 kolumny na adres, bez śledzenia przekierowań, z maksymalnie sześcioma żądaniami równolegle — i umieściłyśmy wynik w wersjonowanym pliku tabelarycznym. Nad nim uruchomiłyśmy osobne sprawdzenia: rzeczywistą kompresję HTML, co jest przesyłane przy każdej nawigacji, co zawierają pakiety JavaScript, jakie fonty są pobierane, jakie nagłówki cache i transportu oferuje serwer. Każda liczba została zweryfikowana w rzeczywistej odpowiedzi, a nie wywnioskowana z konfiguracji.

Co z tego wyszło

244 adresy odpowiadają 200, a 5 przekierowuje. 131 stron nie miało adresu kanonicznego, a 219 z 244 deklarowało stronę główną jako adres udostępniania — oba problemy zostały teraz naprawione jedną linią w konfiguracji bazowej, która stosuje się do każdej trasy. Serwer nie oferuje Brotli ani HTTP/2. Katalog tłumaczeń, 2.268 kluczy, jest przesyłany przy każdej nawigacji i kosztuje około 70 KB po kompresji za każdym razem. Pakiet 443 KB zawiera cztery katalogi językowe, z których tylko jeden jest routowalny. Fonty dostarczają też podzbiór cyrylicy, mimo że sprawdzone strony nie zawierają żadnego znaku cyrylicznego. Wszystkie liczby wraz z komendami, które je odtwarzają, są zapisane w repozytorium.

Czego nie mówi ten przypadek

To są pomiary laboratoryjne, wykonane z zewnątrz, z bezpośrednimi żądaniami. Nie są to dane terenowe od rzeczywistych odwiedzających i nie przedstawiamy ich jako takich: metryki odczuwanego czasu ładowania nie mogły zostać odczytane w użytym narzędziu i są wyraźnie oznaczone jako niemierzone. Nie uruchomiłyśmy budowania aplikacji podczas audytu, ponieważ kilka osób pracowało na tym samym checkoutcie.

Pytania

O co pytają ludzie, zanim zadzwonią

Na czym dokładnie budujecie?

Next.js 16.2.4 z React 19.1.0 i TypeScript, z Tailwind do stylów i dostępnymi komponentami interfejsu opartymi na prymitywach Radix. Strony są prerenderowane przy budowaniu i serwowane z cache — potwierdza się to z zewnątrz: nagłówki odpowiedzi zawierają `x-nextjs-prerender: 1` oraz `x-nextjs-cache: HIT`. To nie jest lista technologii, którą przeczytałyśmy; to stos, na którym działa strona, którą właśnie czytasz.

Jak samodzielnie sprawdzę to, co mówicie o bezpieczeństwie?

Jedną komendą: `curl -I https://www.megapromoting.com/servicii`. Zobaczysz `strict-transport-security: max-age=63072000; includeSubDomains; preload`, `x-content-type-options: nosniff`, `x-frame-options: SAMEORIGIN`, `referrer-policy: strict-origin-when-cross-origin`, politykę uprawnień, która zamyka kamerę i zostawia mikrofon tylko dla własnego originu, plus politykę bezpieczeństwa treści z wyraźną listą originów. Pierwsze pięć pochodzi z konfiguracji aplikacji; ostatnia jest wysyłana przez serwer WWW — dwa różne miejsca, i tak to zapisujemy przy przekazaniu.

Skąd wiecie, że niczego nie zepsułyście przy ostatniej publikacji?

Ze skryptu akceptacyjnego uruchamianego po publikacji. Otwiera każdą stronę produktu i przerywa, jeśli brakuje kodu 200, kotwicy pytań, kotwicy przykładu lub adresu kanonicznego; następnie sprawdza, że mapa witryny zawiera każdy produkt i nie zawiera niedziałających wariantów językowych oraz że `robots.txt` nie blokuje zasobów renderowania. Każde sprawdzenie z listy odpowiada czemuś, co już wcześniej się zepsuło. Skrypt jest przekazywany wraz z projektem — można go też uruchomić samodzielnie.

Czy Wasza strona jest szybka?

Zależy od tego, co mierzysz, i mamy liczby w obu kierunkach. Dobre: strony są prerenderowane i serwowane z cache, obrazy wychodzą w AVIF i WebP z rocznym cache, czcionki są hostowane lokalnie. Złe, mierzone na własnej stronie: serwer nie obsługuje Brotli ani HTTP/2 — żądanie z `Accept-Encoding: br` dostaje odpowiedź bez kompresji; katalog tłumaczeń jest przesyłany przy każdej nawigacji i kosztuje około 70 KB skompresowane za każdym razem; pakiet 443 KB zawiera cztery katalogi językowe, z których tylko jeden jest routowalny. Nie daję Ci wyniku laboratoryjnego; daję Ci zmierzone bajty i listę napraw, która z nich wynika.

Kto utrzymuje mapę witryny?

Nikt, i to jest poprawna odpowiedź. Generuje się z pięciu źródeł danych — stałych adresów, artykułów, produktów, usług i kombinacji usługa × domena — i przechodzi przez końcową deduplikację. Wychodzi 147 adresów, ta sama liczba w kodzie i w pliku serwowanym w produkcji. Nowa strona wchodzi automatycznie. Czego dziś brakuje, aby to powiedzieć: wpisy nie mają daty ostatniej modyfikacji, a 93 adresy, które można indeksować, nie są jeszcze w mapie. Są na liście napraw, nie ukryte.

Robicie wielojęzyczne strony?

Tutaj muszę być precyzyjna, bo to jest najjaśniejsze ograniczenie tej strony. Przełączanie języka w adresie nie działa: konfiguracja na stałe ustawia rumuński, więc detektor nigdy nie czyta parametru. Napisałam w repozytorium, dlaczego oczywiste rozwiązanie jest gorsze — przy renderowaniu po stronie serwera nie ma ani local storage, ani browsera, więc detektor spada na angielski i wszystkie strony wychodzą po angielsku — oraz jakie są dwa realne rozwiązania: routy ścieżkowe z segmentem języka albo rozwiązywanie języka na serwerze przy każdej stronie. Pierwsze jest rekomendowane. Dla nowego projektu startujemy od razu z routami ścieżkowymi; dla istniejącego to praca, nie ustawienie.

Co się dzieje ze starymi adresami, kiedy przebudowujecie stronę?

Są inwentaryzowane i każdy dostaje decyzję: zostaje, jest przekierowany na stałe albo znika. Przy porządkach na tej stronie wyszły 43 przekierowania w konfiguracji. Jest jeszcze 11 stron, które przekierowują wewnątrz aplikacji — działają, ale budują stronę przed wysłaniem odpowiedzi przekierowania, co jest stratą; są na liście do przeniesienia do konfiguracji. Mówię Ci to, żebyś wiedziała, jakiego rodzaju lista trafia przy przekazaniu.

Skąd wiem, że formularz naprawdę dostarcza?

Pytasz go: `GET /api/health/contact` odpowiada 200, jeśli lead może teraz trafić do człowieka, i 503, jeśli nie, osobno sprawdzając, że token kanału powiadomień jest ważny i że dziennik żądań da się zapisać. Odpowiedź zawiera tylko wartości logiczne, nigdy token. Istnieje dlatego, że dokładnie tutaj coś się kiedyś urwało: token został cofnięty, trasa zwracała 500, żądania ginęły bez śladu. Teraz żądanie zapisuje się w dzienniku, zanim spróbuje się dostarczenia.

Czego nie robicie?

Nie obiecujemy pozycji w wyszukiwarce, procentów konwersji ani wyników wydajności, których nie zmierzyliśmy na Twoim projekcie. Nie dostarczamy strony bez listy starych adresów i bez procedury powrotu. Nie bierzemy odpowiedzialności za platformy zewnętrzne, do których nie mamy dostępu. I nie przedstawiamy jako gotowego czegoś, co ma znane ograniczenie — jeśli mam ograniczenie, znajdziesz je zapisane w repozytorium, zanim znajdziesz je w produkcji.

Na czym opierają się powyższe stwierdzenia (15 źródeł)
  1. Producția servește pagini prerandate din 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. Antete de securitate în răspunsul real: HSTS `max-age=63072000; includeSubDomains; preload`, `nosniff`, `SAMEORIGIN`, `strict-origin-when-cross-origin`, politică de permisiuni cu `microphone=(self)`; plus o politică de securitate a conținutului completă servită de nginx și ABSENTĂ din `next.config.ts`https://www.megapromoting.com/servicii · 2026-09-06

13 z nich to kod i pliki z naszych repozytoriów. Nie publikujemy ich nazw ani numerów linii: razem, na jednej stronie, opisałoby to zbyt dokładnie, jak zbudowane są systemy, które nie należą tylko do nas. Przechodzimy je razem z Tobą, w repozytorium, na życzenie — weryfikacja pozostaje możliwa, tylko odbywa się w rozmowie.

Co chcesz, żeby działało lepiej?

Opowiedz nam o swoim procesie. Wspólnie ustalimy, co warto zbudować, co da się połączyć i jak sprawdzimy wynik.

Porozmawiajmy