Skip to content

Dark mode, kliensoldali hibakovetes es Playwright e2e - #79

Merged
Xentinus merged 3 commits into
masterfrom
feat/td-50-61-60-darkmode-hibakovetes-e2e
Aug 22, 2026
Merged

Dark mode, kliensoldali hibakovetes es Playwright e2e#79
Xentinus merged 3 commits into
masterfrom
feat/td-50-61-60-darkmode-hibakovetes-e2e

Conversation

@Xentinus

@Xentinus Xentinus commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Három issue, három commit. Egymásra épülnek: a dark mode hozza a témaválasztást, a hibakövetés
használja a shared modul-mintát, az e2e pedig mindkettőt megnézi böngészőben.

Dark mode a publikus oldalon és az adminban — closes #50

A 17 token 40-re bővült, és megkapta a sötét párját két szelektor alatt:
@media (prefers-color-scheme: dark) :root:not([data-theme='light']) a rendszer-preferencia,
[data-theme='dark'] a kézi választás. A :not() azért kell, hogy a kifejezett „világos" nyerjen
egy sötétre állított gépen is.

A munka nagyobb része viszont nem a paletta volt: 59 fix szín állt a komponensek scoped style
blokkjaiban (túlnyomó részt background: #fff és color: #fff), és mivel :deep/:global nincs
az egész repóban, a tokenek öröklődése az egyetlen csatorna a komponensek felé.

  • A sötét paletta nem a világos invertálása: minden token a szerepét tartja. A gray skála ezért
    fordul meg, a felszínek viszont a világos paletta sorrendjét tartják
    (--surface > --bg > --surface-3 > --surface-2), tehát egy kártya továbbra is kiemelkedik,
    egy halk kitöltés továbbra is besüpped. Invertálva minden kiemelt chip bemélyedéssé fordult volna.
  • Kontraszt WCAG AA-ra mérve minden szoveg-tokenre, a számok a base.css kommentjében. A --danger
    két tokenre vált szét: szöveghez elég világos vörös nem tud fehér feliratot vinni.
  • Új shared composable: useTheme (pf_theme, a useLang mintájára). Három állapot, nem kettő
    — a „system" önálló választás, és egy két-állású kapcsoló az első kattintással csendben lepinnelné
    a témát. System módban a data-theme attribútum nincs kiírva, tehát a rendszerbeállítás menet
    közbeni váltása JavaScript nélkül is átszínezi az oldalt.
  • public/theme.js mindkét appban: a tárolt témát a stylesheet előtt írja ki. Külön fájl és nem
    inline script, mert a CSP script-src 'self' nonce nélkül — ugyanaz az indok, mint az
    /error.js-nél.
  • A Turnstile widget témája eddig hard-kódolt "light" volt („the site has no dark mode"); most a
    feloldott témára van kötve. Nem 'auto'-ra: az a rendszert követi, ami épp akkor rossz válasz,
    amikor a látogató felülírta.
  • Az error.html saját, bundle nélküli paletta-másolata is megkapta a sötét párját. Ez az az oldal,
    ahova a látogató akkor kerül, amikor már valami baj van.

Kliensoldali hibakövetés a két frontendben — closes #61

Szerveroldalon volt hibakövetés (Serilog, ErrorId), kliensoldalon semmi: egy JavaScript kivétel,
egy törött chunk-betöltés vagy egy hibás API-válasz-kezelés a látogató böngészőjében történt, és
soha nem tudtunk róla.

Az issue első célja a self-hosted GlitchTip volt; ez a minimál változat. Indok: a jelentések a
már meglévő Serilog-folyamba mennek, tehát nincs új szolgáltatás a 2 GB-os VPS-en, nincs új
memórialimit, nincs új üzemeltetési felület — és a connect-src 'self' már fedi az endpointot,
tehát a CSP-t sem kell nyitni.

  • Új shared modul: utils/errorReporter.ts. window.onerror + unhandledrejection +
    app.config.errorHandler + router.onError. Mind a négy kell: a Vue elkapja a komponens
    hibákat, tehát azok nem jutnak el a window.onerror-ig, a lazy view chunkja pedig navigáció
    közben hasal el, nem komponensben.
  • Szándékosan nem a http.ts-en keresztül küld: az a wrapper éppen az egyik bejelentett dolog,
    és egy reporter, ami dob vagy újrapróbál, rosszabb, mint a semmi.
  • Az endpoint (POST /api/activity/error) a Core-ban van és nem a Serverben, tehát mindkét host
    kiszolgálja, és mindkét app a saját originjára jelent. Ha az admin a publikus hostra küldene,
    ahhoz CORS kellene ott és szélesebb connect-src az admin CSP-ben — semmiért.
  • traceId összekötés: az 5xx a ProblemDetails traceId-jével megy be, tehát a kliensoldali tünet és
    a szerveroldali ok egy grep-pel összerakható. A 4xx szándékosan nem — az a szerver helyes
    válasza, nem defekt. A status 0 viszont igen: arról szerveroldalon definíció szerint nincs semmi.
  • Adatvédelem: nincs query string, hash és űrlap-tartalom, a POST Referer fejléce
    referrerPolicy: 'origin' miatt csak az origint viszi. Amit strukturálisan nem lehet szűrni: egy
    kivétel szövege idézhet felhasználói bemenetet — ezt a 300 karakteres korlát határolja.
  • Log-injection: minden mező támadó-kontrollált szöveg, egy sortörés a közepén hamisított második
    log sor. A Clamp " | "-re váltja a sortöréseket (ez tartja el a stack frameket is).
  • Source map: build.sourcemap: 'hidden' — a mapok elkészülnek, de sourceMappingURL komment nem
    kerül a bundle-be, és a .map fájlok törlődnek a wwwrootból a publish előtt. A visszafejtés
    menete a RUNBOOK 12. szekciójában.
  • CLIENT_ERRORS_ENABLED kapcsoló mindkét hostra, a deploy.yml-en is átvezetve — a deploy minden
    alkalommal újraírja a VPS .env-jét, tehát nélküle a kikapcsolás az első master pushnál csendben
    visszaállt volna.

Ami kimaradt: az uptime figyelés. Az issue maga is külön tételnek nevezi; a /health mindkét
hoston megvan, csak nincs, ami kívülről nézze — ez a RUNBOOK 12. szekciójának végén rögzítve van.

Playwright e2e smoke a teljes stackre — closes #60

Eddig senki nem nyitott meg egy böngészőt az összeállított stacken, a deploy utáni smoke pedig
státuszkódot ellenőriz, nem működést. Hét spec az issue listája szerint:

Spec Mit fed, amit más nem ér el
pages.spec.ts státuszkód és a mögötte megjelenített oldal együtt — az SPA nem tud státuszkódot állítani, tehát a szerver dönt a saját útvonal-táblájából, a böngésző arról, mit rajzol
head.spec.ts a szerveroldali head-írás (SpaShell) és a kliensoldali useDocumentMeta együtt. A hiba itt némán áll elő: minden megosztott link „Portfólió"-ként bomlik ki, közben a böngésző füle helyesnek látszik
contact.spec.ts a teljes kör a Turnstile mindig-átmenő teszt kulcsaival
language.spec.ts nyelvváltás, és hogy megmarad kliensoldali navigáció és teljes újratöltés után is
theme.spec.ts a #50-ben bekerült témaválasztás (nem az issue listájának tétele, de ugyanebben a branchben landolt)
analytics.spec.ts a ?notrack=1 kizárás — a mechanizmus maga a böngésző-tároló plusz a navigáció
cache-outage.spec.ts a ContentCache fail-open ága leállított Redisszel, külön futásban
  • A CI job saját, cache-ből épülő web image-et húz fel --wait-tel. Az admin nem indul: ahhoz
    Cloudflare Access assertion kellene, az kimarad az első körből.
  • workers: 1 és fullyParallel: false. Ez nem figyelmetlenség: minden kérés egy kliens IP-ről
    jön, a host pedig kliensenként limitál (240/perc, 60/perc útvonalanként) — egy párhuzamos suite
    429-eket kapna, és a hiba bárminek látszana, csak rate limitnek nem. Ugyanezért kell a suite-nak
    kicsinek maradnia; a komment a configban van, mert a következő teszt írójának szól.
  • Trace és képernyőkép artifact hibánál — enélkül a CI-ban elhasalt e2e nem debuggolható.
  • A deploy/smoke-test.sh változatlan: az e2e a PR-t védi, a smoke a kiadást.

Ami kimaradt: az axe-core és a Lighthouse mérés. Az issue szerint ugyanebben a jobban
futtatható, de a Playwright bevezetése önmagában is megáll, és egy külön tételt nem érdemes ide
csomagolni.

Amit az első e2e futás hozott felszínre

A suite első CI futása 19 zöldet, 3 hibát és 1 flaky-t adott — mindhárom hiba a saját specjeimben
volt, a flaky viszont nem:

  • A trace szerint a /assets/HomeView-*.js 429-et kapott, ezért nem töltődött be a SPA. A rate
    limit a statikus asseteket is számolja (240 kérés/perc/kliens), és egy friss böngésző-contextből
    induló oldalbetöltés ~14 kérés. Élesben ez ritkán harap, mert a Cloudflare cache-eli a hash-elt
    asseteket — CDN nélkül viszont minden oldalbetöltés a teljes asset-készletbe kerül az originnél.
  • Ezért lett a két kérés-budget configból felülírható (RateLimitOptions). A default 0 = a hostba
    épített érték, tehát éles viselkedés nem változik
    , és a .env.example kimondja, hogy élesben
    0-n kell maradnia. Az e2e job viszi feljebb, és a deploy.yml szándékosan nem írja a VPS
    .env-jébe: ez környezet-alakra szóló felülírás, nem üzemeltetési kapcsoló.
  • A cache-kimaradás tesztjei is elhasaltak, és a trace itt is megmutatta, miért: a böngésző négy
    tartalmi endpointját a szerver meg sem kapta — a kérések ott vártak, amíg a Redis-kliens
    észrevette, hogy nincs kapcsolat. A fájl ezért egyszer, előre „felmelegíti" a felismerést, és a
    tesztek utána a beállt állapotot mérik: a kérdés az, hogy kimaradás alatt működik-e az oldal,
    nem az, hogy a kimaradás pillanatában is azonnal gyors-e.

A javítások után a fő suite 23/23 zöld 13,7 másodperc alatt, a kimaradás-készlet 3/3.

Az oldal csak vilagos temat tudott: a prefers-color-scheme nulla talalat
volt a repoban, a base.css :root blokkja egyetlen fix palettat
definialt. Rendszerszintu dark mode mellett ez kiugro, es a latogatok
egy resze szamara kellemetlen.

A szinek mar tokenekben voltak, de a tokenek mellett 59 fix szin allt a
komponensek scoped style blokkjaiban - tulnyomo reszt "background: #fff"
es "color: #fff". Ezek nem tudnak temat kovetni, es mivel minden style
blokk scoped (nincs :deep sem :global az egesz repoban), a tokenek
oroklodese az EGYETLEN csatorna a komponensek fele. Ezert a munka nagyobb
resze nem uj paletta, hanem a fix szinek visszavezetese tokenre.

- base.css: a vilagos paletta 17 tokenje 40-re bovult, es megkapta a
  parjat. Uj tokenek arra, aminek eddig nem volt: --on-accent /
  --on-ink / --on-danger (elotersznin egy kitoltott felszinen),
  --surface-alpha, --nav-bg, --overlay, --shadow-sm, --scrollbar-thumb,
  --hatch(-strong), --border-4, --accent-bg-strong, --danger-bg /
  --danger-border, --warn-bg / --warn-ink, --code-*-rgb, --viz-1..8 /
  --viz-other.
- A sotet blokk ket szelektor alatt all: @media (prefers-color-scheme:
  dark) :root:not([data-theme='light']) a rendszer-preferencia, es
  [data-theme='dark'] a kezi valasztas. A media blokk azert van
  :not()-tal szukitve, hogy a kifejezett "vilagos" nyerjen egy sotetre
  allitott gepen is. A duplikacio szandekos: egy szabaly nem lehet
  egyszerre a media queryn belul es kivul, a light-dark() pedig egy
  regebbi bongeszon az OSSZES tokent egyszerre ervenytelenne teszi -
  az nem vilagos oldal, hanem csupasz.
- A sotet paletta nem a vilagos invertalasa, minden token a SZEREPET
  tartja. A gray skala ezert fordul meg (a --gray-700 a legerosebb
  masodlagos szoveg mindket temaban, tehat sotet hatteren a
  legvilagosabb), a felszinek viszont a vilagos paletta SORRENDJET
  tartjak: --surface > --bg > --surface-3 > --surface-2 vilagossag
  szerint, tehat egy kartya tovabbra is kiemelkedik a lapbol, egy halk
  kitoltes (hover sor, progress sav, toggle vajata) tovabbra is besuvad.
  Az invertalas minden kiemelt chipet bemelyedesse forditott volna.
- Kontraszt (WCAG AA) a sotet paletta minden szoveg-tokenjere merve, a
  szamok a base.css kommentjeben. A --danger ket tokenre valt szet:
  szoveghez eleg vilagos voros nem tud feher feliratot vinni, ezert a
  szolid destruktiv gomb --danger-solid(-hover)-t hasznal.
- Uj shared composable: useTheme (pf_theme kulcs, useLang mintajara).
  Harom allapot, nem ketto - a "system" onallo valasztas, es egy
  ket-allasu kapcsolo az elso kattintassal csendben lepinnelne a temat.
  System modban a data-theme attributum NINCS kiirva: igy a media query
  dont, es a rendszerbeallitas menet kozbeni valtasa JavaScript nelkul
  is atszinezi az oldalt (a composable csak a theme-color metat koveti).
- public/theme.js mindket appban: a tarolt temat a stylesheet elott irja
  ki, tehat a kifejezett valasztas nem villantja fel a masik palettat.
  Kulon fajl es nem inline script, mert a CSP script-src 'self' nonce
  nelkul - ugyanaz az indok, mint az /error.js-nel. A <head>-ben
  blokkolva, a Vite altal beszurt stylesheet elott.
- ThemeToggle a publikus nav-ba a LangToggle melle, es a DetailNav-ba
  (ott a showLang-tol fuggetlenul: a nyelv egynyelvu lapon elrejtozik, a
  tema oldalszintu preferencia). Az adminban a sidebar lababa, oszlopba
  igazitva. A cimkek a uiCommon-ban, mert mindket app hasznalja.
- Turnstile: a widget temaja eddig hard-kodolt "light" volt, a komment
  szerint "the site has no dark mode". Most a feloldott temara van kotve
  - nem 'auto'-ra, mert az a rendszert koveti, ami epp akkor rossz
  valasz, amikor a latogato felulirta. Temavaltasra a widget
  ujrarendelodik (a Turnstile-nak nincs API-ja elo widget atszinezesere),
  tehat a kihivas ujra kiadodik.
- SkillsDonut: a nyolcas kategorikus paletta a base.css-be kerult
  temankent, es a szeletek :style-on kapjak a szint, nem a stroke
  attributumon - SVG presentation attributumban a var() nem
  behelyettesitodik, stroke="var(--viz-1)" semmit nem rajzolna.
- CodeBackdrop: a nyolc kulonbozo alfa miatt a ket arnyalat csatorna-
  harmaskent jon a tokenbol, rgb(var(--code-ink-rgb) / 3%) formaban. A
  maszkban levo #000 marad: a maszk luminanciat olvas, nem szint.
- error.html: sajat, bundle nelkuli paletta-masolata megkapta a sotet
  parjat, es betolti a /theme.js-t. Ez az az oldal, ahova a latogato
  akkor kerul, amikor mar valami baj van - vilagos villanas nelkul.
- Ket szandekos kivetel maradt fix szinnek, kommenttel: a JPEG
  lapositas feher alapja az imageEdit.ts-ben (a tarolt kepbe sul bele,
  nem kovetheti a szerkeszto temajat) es a CodeBackdrop maszkja.
- A site.webmanifest theme_color/background_color valtozatlan: a
  manifest nem tud temara reagalni, telepitett PWA-nal a splash igy
  vilagos marad.

- A ThemeToggle harom glyphje utan U+FE0E (text presentation selector)
  all: egyik sincs a betoltott fontsource latin subsetekben, tehat
  platform-fallback fontbol jonnek, es a U+2600-nak van emoji formaja is
  - enelkul a monokrom pill egyik gombja Androidon szines nap lenne.

Closes #50
Szerveroldalon volt hibakovetes (Serilog, UseSerilogRequestLogging,
hibaoldal ErrorId-vel), kliensoldalon semmi: egy JavaScript kivetel, egy
torott chunk-betoltes vagy egy hibas API-valasz-kezeles a latogato
bongeszojeben tortent, es soha nem tudtunk rola. A content store
elkapta az API-hibat es a HomeView megjelenitette a panelt, de hogy ez
hanyszor fordult elo es miert, arrol nem volt adat.

Az issue elso celja a self-hosted GlitchTip volt; ez a minimal valtozat
lett. Indok: a jelentesek a mar meglevo Serilog-folyamba mennek, tehat
nincs uj szolgaltatas a 2 GB-os VPS-en, nincs uj memorialimit, nincs uj
uzemeltetesi felulet - es a `connect-src 'self'` mar fedi az endpointot,
tehat a CSP-t sem kell nyitni.

- Uj shared modul: utils/errorReporter.ts. Bekoti a window.onerror-t es
  az unhandledrejection-t, ad egy vueErrorHandler-t az
  app.config.errorHandler-hez, es egy reportCaughtError-t a
  router.onError-hoz. Mind a negy kell: a Vue elkapja a komponens
  hibakat, tehat azok nem jutnak el a window.onerror-ig, a lazy view
  chunkja pedig navigacio kozben hasal el, nem komponensben.
- Szandekosan NEM az api/http.ts-en keresztul kuld. Az a wrapper eppen
  az egyik bejelentett dolog, es egy reporter, ami dob (vagy ujraprobal,
  vagy spinnerbe idozit tul), rosszabb, mint a semmi: minden kuldes
  fire-and-forget, elnyelt hibaval, mint a latogatas-beacon.
- Uj endpoint: POST /api/activity/error. A Core-ban van es nem a
  Serverben, tehat MINDKET host kiszolgalja, es mindket app a sajat
  originjara jelent. Ha az admin a publikus hostra kuldene, ahhoz CORS
  kellene ott es szelesebb connect-src az admin CSP-ben - semmiert: egy
  admin oldali kivetel ma pont annyira lathatatlan, mint egy publikus.
  Az "activity" prefix ugyanazert van, mint a beaconnal: az adblocker
  szurolistak a telemetriara hasonlito URL-eket blokkoljak.
- A jelentes Warning szinten megy a logba, nem Error szinten: kliensoldali
  hiba valodi defekt, de nem ez a process hasal el, es az Error az, amire
  egy riasztas kotne. A traceId a szovegben is szerepel, nem csak
  propertykent: a `grep <id>` a szerveroldali sort es ezt is megtalalja.
- traceId osszekotes: a http.ts az 5xx-et a ProblemDetails traceId-jevel
  jelenti be, tehat a kliensoldali tunet es a szerveroldali ok egy grep-pel
  osszerakhato. A 4xx szandekosan nem megy be - egy 400, 404, 409 vagy
  429 a szerver helyes valasza es a UI megjelenitett hibaja, nem defekt,
  es bejelentve elnyomna az igaziakat. A status 0 (a keres el sem ert a
  szerverig) viszont bemegy: az a fajta, amirol szerveroldalon
  definicio szerint nincs semmi.
- Adatvedelem: nem megy be query string, hash es beirt urlap-tartalom, a
  POST Referer fejlece pedig `referrerPolicy: 'origin'` miatt csak az
  origint viszi (same-origin keresnel a strict-origin-when-cross-origin
  a teljes URL-t adna). Ami strukturalisan nem szurheto: egy kivetel
  SZOVEGE idezhet felhasznaloi bemenetet - ezt a 300 karakteres korlat
  hatarolja, nem szunteti meg. A kommentek ezt kimondjak.
- Zajszures: a kliens eldobja a cross-origin "Script error."-t (a
  bongeszo mindent visszatart, nincs mire ranezni), a ResizeObserver
  loop ertesitest es a bovitmeny-eredetu hibakat; a szerver eldobja a
  bot user agentet (ugyanaz a BotDetection, mint a beaconnal). Azonos
  jelentes egyszer megy el, oldalbetoltesenkent legfeljebb ot, es az
  endpointnak sajat rate limit policyja van, kliensenkent tiz percenkent.
  A policy a RateLimitPolicies-ben van es MINDKET host regisztralja: egy
  olyan policy, amit a host nem regisztralt, keres kozben dob, nem
  indulaskor.
- A chunk-hibakat a reporter atsorolja `chunk` fajtara. Ez nem kodhiba:
  a ful betoltese ota volt egy deploy, es a kert hash-elt chunk mar nincs
  az originen - mas a teendo, tehat mas fajta.
- Log-injection: minden mezo tamado-kontrollalt szoveg, es egy sortores
  a kozepen egy hamisitott masodik log sor. A Clamp " | "-re valtja a
  sortoreseket (ez tartja el egymastol a stack frameket is) es kicsereli
  a tobbi kontroll karaktert.
- A DTO minden mezoje nullable es egyik sem visel validacios attributumot,
  a RecordViewRequest-tel ellentetben: a jelentes olyan uton erkezik, ami
  soha nem olvassa a valaszt, tehat egy 400 nem javit semmit - csak
  elveszti a jelentest, mikozben eppen a mar hibasan mukodo klienstol
  erkezo jelentes a legerdekesebb. Az endpoint maga validal es klampol,
  es minden esetben 204-et ad, a kiszurt jelentesekre is: a hivo nem tud
  mit tenni egy verdikttel, es egy megkulonboztetheto elutasitas
  megmondana egy probolgatonak, mik a szurok.
- Source map: `build.sourcemap: 'hidden'` mindket appban - a mapok
  elkeszulnek, de sourceMappingURL komment nem kerul a bundle-be. Az
  image buildbol a .map fajlok torlodnek a wwwroot-bol a publish elott
  (a map maga a forraskod, azt a publikus origin nem szolgalhatja ki),
  visszafejteshez ugyanazon a commiton kell ujraepiteni - a stackben levo
  fajlnev hash-e mondja meg, melyik build volt. A menete a RUNBOOK 12.
  szekciojaban.
- CLIENT_ERRORS_ENABLED kapcsolo mindket hostra. Nem meretezes: a
  jelentes egyenesen a logba megy, tehat nincs mit meretezni - ez arra
  van, hogy egy zajos vagy visszaelesszeru bejelentest image build nelkul
  el lehessen hallgattatni. A log kontenerenkent 3 x 10 MB-ra rotal,
  tehat egy minden oldalbetoltesnel elsulo hiba elnyomhatja a tobbit.
- Az uptime figyeles nem keszult el: az issue maga is kulon tetelnek
  nevezi. A /health mindket hoston megvan, csak nincs, ami kivulrol
  nezze - ez a RUNBOOK 12. szekciojanak vegen rogzitve van.

- A deploy minden alkalommal ujrairja a VPS .env-jet a repository
  secretekbol, tehat a CLIENT_ERRORS_ENABLED-nek at kell menni a
  deploy.yml-en is - kulonben a kikapcsolas az elso master pushnal
  csendben visszaallna. A RUNBOOK ezt kimondja: a .env szerkesztese
  azonnali elhallgattatas, a tartos beallitas a secret.

Closes #61
Repository owner deleted a comment from gitguardian Bot Aug 22, 2026
Xentinus added a commit that referenced this pull request Aug 22, 2026
Nem volt end-to-end teszt. A CI backend unit/API tesztet, frontend
tipusellenorzest, lintet es Vitest komponens-tesztet futtatott, image
buildet es Trivy szkennelest - de senki nem nyitott meg egy bongeszot az
osszeallitott stacken, es a deploy utani smoke HTTP statuszkodot ellenoriz,
nem mukodest.

Ez pont azoknal a hibaknal dragit, ahol a retegek egymasra hatnak, es
amelyek egyik meglevo teszttipussal sem erhetok el - a specek ezt a listat
kovetik:

- pages.spec.ts: statuszkod es a mogotte megjelenitett oldal EGYUTT. Az SPA
  nem tud statuszkodot allitani, tehat a szerver dont a sajat
  utvonal-tablajabol (PublicRoutes), a bongeszo pedig arrol, mit rajzol -
  es a hiba akkor all elo, ha a ketto nem egyezik. Valodi 404 a nem letezo
  slugra, csupasz 404 a pontot tartalmazo utvonalra (scanner-probe),
  /api alatti nem letezo endpoint 404 es nem index.html, es hogy az admin
  iro endpointok nem 401-et, hanem 404-et adnak a publikus hoston: nem
  letezenek ott.
- head.spec.ts: a szerveroldali head-iras (SpaShell) es a kliensoldali
  useDocumentMeta egyutt. A kiszolgalt HTML-ben ott van az oldal sajat
  title-je es canonicalja (a beepitett fallback szandekosan egyiket sem
  tartalmazza, tehat a jelenletuk bizonyitja a templatelest), es mount utan
  a kliens ugyanazt a title-t tartja meg. A hiba itt nemakent all elo:
  minden megosztott link "Portfolio"-kent bomlik ki, kozben a bongeszo fule
  helyesnek latszik.
- contact.spec.ts: a kapcsolati urlap teljes kore a Turnstile
  mindig-atmeno teszt kulcsaival. Amitol megfoghato: a submit gomb addig
  disabled, amig a captchanak nincs tokenje - tehat az engedelyezese
  MAGA a jelzes, hogy a kihivas megvalaszolodott. Plusz az ures submit:
  harom field error es nulla POST.
- language.spec.ts: nyelvvaltas, es hogy megmarad kliensoldali navigacio
  ES teljes ujratoltes utan is (az elso a reaktivitas, a masodik a
  localStorage + module scope). A kulcsot maga is ellenorzi: az /error.js
  a pf_lang-ot olvassa, azt az oldalt viszont 429 provokalasa nelkul nem
  lehet elerni.
- theme.spec.ts: a #50-ben bekerult temavalasztas. Nem az issue listajanak
  tetele, de ugyanebben a branchben landolt, es harom olyan resze van, ami
  csak bongeszoben talalkozik: a media query, a /theme.js altal irt
  attributum es a composable. Rendszer-preferencia attributum nelkul,
  kifejezett vilagos valasztas sotet rendszerbeallitas ellen, es a
  valasztas ujratoltes utan.
- analytics.spec.ts: a ?notrack=1 kizaras. Nincs mit unit tesztelni benne -
  a mechanizmus MAGA a bongeszo-tarolo plusz a navigacio, es a hiba az,
  hogy a tulajdonos csendben latogatokent szamol a sajat statisztikajaban.
- cache-outage.spec.ts: a ContentCache fail-open aga a gyakorlatban.
  Redis nelkul is 200 a fooldal, az API az adatbazisbol valaszol, es a
  PublicRouteIndex is fail-open - ha az fail-closed lenne, egy
  cache-kimaradas alatt az oldal MINDEN lapja 404-et adna.

A CI job:

- Sajat, cache-bol epulo web image (`cache-from: type=gha,scope=web`, iras
  nelkul: ket job ugyanabba a scope-ba irva egymast fejelne le), es a tag a
  compose WEB_IMAGE defaultja, tehat a compose nem buildel ujra.
- `docker compose up -d --wait --wait-timeout 180 web`: csak a web (es a
  depends_on miatt a db + redis). Az `--wait` a healthcheckre var, tehat az
  `up -d` semmit nem bizonyito visszaterese helyett itt hasal el egy nem
  indulo host. Az admin nem indul - ahhoz Cloudflare Access assertion
  kellene -, de a `:?` valtozoi akkor is kellenek, mert a compose a fajl
  egeszet interpolalja.
- SEED_MODE=dev, tehat a tesztek ismert slugokra allhatnak. A slugok egy
  helyen vannak (tests/seed.ts), nem hat specben.
- Trace es kepernyokep artifact feltoltese hibanal: enelkul a CI-ban
  elhasalt e2e nem debuggolhato.
- A cache-kimaradas tesztjei kulon futasban (@needs-outage tag), a Redis
  leallitva - egy spec ezt nem teheti meg magaval anelkul, hogy a suite
  tobbi reszet eltorne. A Redis egy `if: always()` lepesben indul vissza.
- Commitolt package-lock.json, tehat a job `npm ci`-vel megy. A lepes
  ettol fuggetlenul lock nelkul is mukodik (`npm install` fallback), es a
  setup-node cache-e is csak lock mellett kapcsol be - igy egy jovobeli
  lock-torles nem buktatja a jobot, csak lassabb lesz.
- Kulon type-check lepes az e2e-re, a stack felhuzasa elott: a Playwright
  esbuilddel forditja a specekt es egyaltalan nem tipusellenoriz, tehat egy
  spec lehet tipus-ertelmetlen es megis lefut. A tsc az egyetlen, ami ezt
  megfogja.

Egyeb dontesek:

- workers: 1 es fullyParallel: false. Ez nem figyelmetlenseg: minden keres
  egy kliens IP-rol jon, a host pedig kliensenkent limital (240/perc
  osszesen, 60/perc utvonalankent) - egy parhuzamos suite 429-eket kapna,
  es a hiba barminek latszana, csak rate limitnek nem. Ugyanezert kell a
  suite-nak kicsinek maradnia; ez a komment a configban van, mert a
  kovetkezo teszt irojanak szol.
- Csak chromium: a suite az illesztesekre valo, nem bongeszo-kulonbsegekre.
- A deploy/smoke-test.sh valtozatlan marad: az e2e a PR-t vedi, a smoke a
  kiadast. Az e2e a deploy utjan is lefut (a ci.yml ott is meghivodik),
  csak a sajat image-evel.
- Az axe-core es a Lighthouse meres kimaradt: az issue szerint ugyanebben a
  jobban futtathato, de a Playwright bevezetese onmagaban is megall - es
  egy kulon tetelt nem erdemes ide csomagolni.
- Az e2e a .dockerignore-ba kerult: semmi nem kerul belole image-be, a
  .NET stage viszont `COPY . .`-t csinal, tehat enelkul minden
  spec-valtoztatas invalidalna azt a layert.
- Dependabot kulon npm bejegyzes az /e2e-re, nem a harom frontend
  csoportjaba: nem kerul belole semmi egyik appba sem, tehat a
  check-dep-sync.mjs sem nezi, es nincs ok hozzakotni a leptetesuket.

A CI elso futasa (PR #79) 19 zold, 3 hasalt, 1 flaky - a harom
kovetkezmenye itt van:

- contact.spec: a captcha-varas a Turnstile iframe-jere vart, azt viszont
  a mindig-atmeno teszt kulcs NEM hoz letre - a token a
  cf-turnstile-response hidden inputba kerul (a trace szerint
  "XXXX.DUMMY.TOKEN.XXXX"). A varas most arra megy: attached, majd nem
  ures ertek, majd engedelyezett gomb. Mindharom egyiranyu, tehat nincs
  kozteslapot, amin a poller atszaladhat.
- analytics.spec: a waitForLoadState('networkidle') elhasalt, mert a
  kapcsolati urlapon levo Turnstile widget nem hagyja elcsendesedni az
  oldalt. A negativ allitasnak felso korlat kell arra, hogy a beacon MAR
  elsult volna, ha egyaltalan elsul - ez a tartalom megjelenese, mert a
  trackView a router.afterEach-ben fut, meg az API-hivasok elott.
- theme.spec flake: a trace szerint a /assets/HomeView-*.js 429-et
  kapott, tehat a SPA nem toltodott be es nem volt mire kattintani. A
  rate limit a statikus asseteket is szamolja: elesben ez ritkan harap,
  mert a Cloudflare cache-eli a hash-elt asseteket, itt viszont nincs
  CDN, tehat minden teszt friss context-tel a teljes asset-keszletet
  lekeri, es a 240/perc egy ablakon belul elfogy.

Ezert lett a ket keres-budget konfigbol felulirhato (RateLimitOptions,
RateLimit__PerClientPermitLimit / __PerPathPermitLimit). A default 0 =
a hostba epitett ertek, tehat eles viselkedes nem valtozik, es a
.env.example kimondja, hogy elesben 0-n kell maradnia. Az e2e job
viszi feljebb. Egy rate limit amugy is olyan ertek, aminek jo, ha
kornyezetenkent hangolhato.

Kisebb keres-csokkentes is: ket teszt, aminek csak a statuszkod vagy egy
statikus fajl kell, a request fixture-t hasznalja page.goto helyett -
egy keres a tizenot helyett.

Closes #60
@Xentinus
Xentinus force-pushed the feat/td-50-61-60-darkmode-hibakovetes-e2e branch from dfc7241 to 7061a44 Compare August 22, 2026 18:56
Repository owner deleted a comment from gitguardian Bot Aug 22, 2026
Nem volt end-to-end teszt. A CI backend unit/API tesztet, frontend
tipusellenorzest, lintet es Vitest komponens-tesztet futtatott, image
buildet es Trivy szkennelest - de senki nem nyitott meg egy bongeszot az
osszeallitott stacken, es a deploy utani smoke HTTP statuszkodot ellenoriz,
nem mukodest.

Ez pont azoknal a hibaknal dragit, ahol a retegek egymasra hatnak, es
amelyek egyik meglevo teszttipussal sem erhetok el - a specek ezt a listat
kovetik:

- pages.spec.ts: statuszkod es a mogotte megjelenitett oldal EGYUTT. Az SPA
  nem tud statuszkodot allitani, tehat a szerver dont a sajat
  utvonal-tablajabol (PublicRoutes), a bongeszo pedig arrol, mit rajzol -
  es a hiba akkor all elo, ha a ketto nem egyezik. Valodi 404 a nem letezo
  slugra, csupasz 404 a pontot tartalmazo utvonalra (scanner-probe),
  /api alatti nem letezo endpoint 404 es nem index.html, es hogy az admin
  iro endpointok nem 401-et, hanem 404-et adnak a publikus hoston: nem
  letezenek ott.
- head.spec.ts: a szerveroldali head-iras (SpaShell) es a kliensoldali
  useDocumentMeta egyutt. A kiszolgalt HTML-ben ott van az oldal sajat
  title-je es canonicalja (a beepitett fallback szandekosan egyiket sem
  tartalmazza, tehat a jelenletuk bizonyitja a templatelest), es mount utan
  a kliens ugyanazt a title-t tartja meg. A hiba itt nemakent all elo:
  minden megosztott link "Portfolio"-kent bomlik ki, kozben a bongeszo fule
  helyesnek latszik.
- contact.spec.ts: a kapcsolati urlap teljes kore a Turnstile
  mindig-atmeno teszt kulcsaival. Amitol megfoghato: a submit gomb addig
  disabled, amig a captchanak nincs tokenje - tehat az engedelyezese
  MAGA a jelzes, hogy a kihivas megvalaszolodott. Plusz az ures submit:
  harom field error es nulla POST.
- language.spec.ts: nyelvvaltas, es hogy megmarad kliensoldali navigacio
  ES teljes ujratoltes utan is (az elso a reaktivitas, a masodik a
  localStorage + module scope). A kulcsot maga is ellenorzi: az /error.js
  a pf_lang-ot olvassa, azt az oldalt viszont 429 provokalasa nelkul nem
  lehet elerni.
- theme.spec.ts: a #50-ben bekerult temavalasztas. Nem az issue listajanak
  tetele, de ugyanebben a branchben landolt, es harom olyan resze van, ami
  csak bongeszoben talalkozik: a media query, a /theme.js altal irt
  attributum es a composable. Rendszer-preferencia attributum nelkul,
  kifejezett vilagos valasztas sotet rendszerbeallitas ellen, es a
  valasztas ujratoltes utan.
- analytics.spec.ts: a ?notrack=1 kizaras. Nincs mit unit tesztelni benne -
  a mechanizmus MAGA a bongeszo-tarolo plusz a navigacio, es a hiba az,
  hogy a tulajdonos csendben latogatokent szamol a sajat statisztikajaban.
- cache-outage.spec.ts: a ContentCache fail-open aga a gyakorlatban.
  Redis nelkul is 200 a fooldal, az API az adatbazisbol valaszol, es a
  PublicRouteIndex is fail-open - ha az fail-closed lenne, egy
  cache-kimaradas alatt az oldal MINDEN lapja 404-et adna.

A CI job:

- Sajat, cache-bol epulo web image (`cache-from: type=gha,scope=web`, iras
  nelkul: ket job ugyanabba a scope-ba irva egymast fejelne le), es a tag a
  compose WEB_IMAGE defaultja, tehat a compose nem buildel ujra.
- `docker compose up -d --wait --wait-timeout 180 web`: csak a web (es a
  depends_on miatt a db + redis). Az `--wait` a healthcheckre var, tehat az
  `up -d` semmit nem bizonyito visszaterese helyett itt hasal el egy nem
  indulo host. Az admin nem indul - ahhoz Cloudflare Access assertion
  kellene -, de a `:?` valtozoi akkor is kellenek, mert a compose a fajl
  egeszet interpolalja.
- SEED_MODE=dev, tehat a tesztek ismert slugokra allhatnak. A slugok egy
  helyen vannak (tests/seed.ts), nem hat specben.
- Trace es kepernyokep artifact feltoltese hibanal: enelkul a CI-ban
  elhasalt e2e nem debuggolhato.
- A cache-kimaradas tesztjei kulon futasban (@needs-outage tag), a Redis
  leallitva - egy spec ezt nem teheti meg magaval anelkul, hogy a suite
  tobbi reszet eltorne. A Redis egy `if: always()` lepesben indul vissza.
- Commitolt package-lock.json, tehat a job `npm ci`-vel megy. A lepes
  ettol fuggetlenul lock nelkul is mukodik (`npm install` fallback), es a
  setup-node cache-e is csak lock mellett kapcsol be - igy egy jovobeli
  lock-torles nem buktatja a jobot, csak lassabb lesz.
- Kulon type-check lepes az e2e-re, a stack felhuzasa elott: a Playwright
  esbuilddel forditja a specekt es egyaltalan nem tipusellenoriz, tehat egy
  spec lehet tipus-ertelmetlen es megis lefut. A tsc az egyetlen, ami ezt
  megfogja.

Egyeb dontesek:

- workers: 1 es fullyParallel: false. Ez nem figyelmetlenseg: minden keres
  egy kliens IP-rol jon, a host pedig kliensenkent limital (240/perc
  osszesen, 60/perc utvonalankent) - egy parhuzamos suite 429-eket kapna,
  es a hiba barminek latszana, csak rate limitnek nem. Ugyanezert kell a
  suite-nak kicsinek maradnia; ez a komment a configban van, mert a
  kovetkezo teszt irojanak szol.
- Csak chromium: a suite az illesztesekre valo, nem bongeszo-kulonbsegekre.
- A deploy/smoke-test.sh valtozatlan marad: az e2e a PR-t vedi, a smoke a
  kiadast. Az e2e a deploy utjan is lefut (a ci.yml ott is meghivodik),
  csak a sajat image-evel.
- Az axe-core es a Lighthouse meres kimaradt: az issue szerint ugyanebben a
  jobban futtathato, de a Playwright bevezetese onmagaban is megall - es
  egy kulon tetelt nem erdemes ide csomagolni.
- Az e2e a .dockerignore-ba kerult: semmi nem kerul belole image-be, a
  .NET stage viszont `COPY . .`-t csinal, tehat enelkul minden
  spec-valtoztatas invalidalna azt a layert.
- Dependabot kulon npm bejegyzes az /e2e-re, nem a harom frontend
  csoportjaba: nem kerul belole semmi egyik appba sem, tehat a
  check-dep-sync.mjs sem nezi, es nincs ok hozzakotni a leptetesuket.

A CI elso futasa (PR #79) 19 zold, 3 hasalt, 1 flaky - a harom
kovetkezmenye itt van:

- contact.spec: a captcha-varas a Turnstile iframe-jere vart, azt viszont
  a mindig-atmeno teszt kulcs NEM hoz letre - a token a
  cf-turnstile-response hidden inputba kerul (a trace szerint
  "XXXX.DUMMY.TOKEN.XXXX"). A varas most arra megy: attached, majd nem
  ures ertek, majd engedelyezett gomb. Mindharom egyiranyu, tehat nincs
  kozteslapot, amin a poller atszaladhat.
- analytics.spec: a waitForLoadState('networkidle') elhasalt, mert a
  kapcsolati urlapon levo Turnstile widget nem hagyja elcsendesedni az
  oldalt. A negativ allitasnak felso korlat kell arra, hogy a beacon MAR
  elsult volna, ha egyaltalan elsul - ez a tartalom megjelenese, mert a
  trackView a router.afterEach-ben fut, meg az API-hivasok elott.
- theme.spec flake: a trace szerint a /assets/HomeView-*.js 429-et
  kapott, tehat a SPA nem toltodott be es nem volt mire kattintani. A
  rate limit a statikus asseteket is szamolja: elesben ez ritkan harap,
  mert a Cloudflare cache-eli a hash-elt asseteket, itt viszont nincs
  CDN, tehat minden teszt friss context-tel a teljes asset-keszletet
  lekeri, es a 240/perc egy ablakon belul elfogy.

Ezert lett a ket keres-budget konfigbol felulirhato (RateLimitOptions,
RateLimit__PerClientPermitLimit / __PerPathPermitLimit). A default 0 =
a hostba epitett ertek, tehat eles viselkedes nem valtozik, es a
.env.example kimondja, hogy elesben 0-n kell maradnia. Az e2e job
viszi feljebb. Egy rate limit amugy is olyan ertek, aminek jo, ha
kornyezetenkent hangolhato.

Kisebb keres-csokkentes is: ket teszt, aminek csak a statuszkod vagy egy
statikus fajl kell, a request fixture-t hasznalja page.goto helyett -
egy keres a tizenot helyett.

A masodik futas mar zold fo suite-ot adott; a cache-kimaradas lepese
viszont elhasalt, es a trace megmutatta, miert: a bongeszo negy tartalmi
endpointjat meg SEM kapta meg a szerver - a keresek ott vartak, amig a
Redis-kliens eszrevette, hogy nincs kapcsolat. Ugyanezert volt gyors a
kozvetlenul utana futo egy-hivasos API teszt. A fajl ezert most egyszer,
elore "felmelegiti" a felismerest egy worker-scope keresben, es a
tesztek utana a mar beallt allapotot merik - a kerdes az, hogy KIMARADAS
ALATT mukodik-e az oldal, nem az, hogy a kimaradas pillanataban is
azonnal gyors-e. A latencia maga a fail-open alku lenyege, ezert kaptak
ezek a tesztek nagyobb idokorlatot is.

Closes #60
@Xentinus
Xentinus force-pushed the feat/td-50-61-60-darkmode-hibakovetes-e2e branch from 7061a44 to bf965b6 Compare August 22, 2026 19:03
@gitguardian

gitguardian Bot commented Aug 22, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@Xentinus
Xentinus merged commit 664fcb1 into master Aug 22, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant