Record what landed, what is in flight, and what remains so later deploys can pick up the plan without archaeology.
17 KiB
Seveda. Spodaj je celoten pregled, kaj smo pri SkinbaseNova performance/legacy cleanup že uredili, kaj je trenutno v teku in kaj še ostaja v planu.
1. M1 — Recommendation nightly jobs
Uredili smo background recommendation jobs:
- popravljena
retry_afterlogika, - uvedeni batchi,
- ohranjena kompatibilnost serialized jobov,
- preprečeno podvajanje/dolgotrajno visenje queue jobov.
Status:
M1 ✅ COMPLETE
2. M2 — Mail queue
Mail pošiljanje je bilo prestavljeno oziroma urejeno prek queue sistema, da mail requesti ne blokirajo HTTP requestov.
M2 ✅ COMPLETE
3. M3 — Sitemap optimizacija
Urejeno generiranje sitemapov, da niso nepotrebno dragi oziroma blokirajoči.
M3 ✅ COMPLETE
4. M4 — Recommendation read path
Optimiziran read path za recommendations:
- manj nepotrebnih queryjev,
- boljša uporaba že pripravljenih podatkov,
- brez spremembe recommendation algoritma.
M4 ✅ COMPLETE
5. M5 — Metrics cleanup
Uredili smo pruning starih metrics podatkov:
retention = 30 dni
Brez agresivnega zmanjševanja zgodovine.
M5 ✅ COMPLETE
6. M6 — Memory / PHP-FPM audit
Pregledali smo:
- PHP-FPM procese,
- memory usage,
- worker sizing,
- server obremenitev.
Pomembno: nismo povečevali workerjev ali spreminjali FPM sizinga, ker ni bilo dokaza, da je to pravi bottleneck.
M6 ✅ COMPLETE
7. M7 — Queue isolation / dedup / presence
Urejeno:
- boljša izolacija queue jobov,
- deduplication,
- omejeno online/presence delo,
- preprečevanje nepotrebnih Redis operacij.
M7 ✅ COMPLETE
8. M8 — Redis cleanup
Uredili smo bounded Redis cleanup.
Nismo uporabljali nevarnih stvari kot:
SMEMBERS na ogromnih setih
DEL velikih keyjev
Redis restart
flushall
M8 ✅ COMPLETE
9. M9 — Scheduler / cron
Uredili smo production scheduler in cron ownership.
M9 ✅ COMPLETE
10. M10 — Database cleanup
Uredili večino DB problemov in query/index cleanup.
Pomembna izjema:
dangerous snapshot migration ❌ NE SME biti izvedena
Ker bi odstranila uporaben production index:
idx_bucket_artwork(bucket_hour, artwork_id)
Ta index smo namenoma ohranili.
M10 ✅ COMPLETE
razen blokirane nevarne migracije
11. M11 — Endpoint performance
Prvi sistematični endpoint performance pregled.
Od tu naprej smo začeli meriti realne HTTP stroške namesto ugibanja.
M11 ✅ COMPLETE
12. M12 — Observability / performance logging
To je bil velik milestone.
Dodali smo nginx JSON performance log:
/var/log/nginx/skinbase-performance.log
Dodali smo:
- Laravel slow HTTP middleware,
- threshold okoli 750 ms,
Server-Timing,- 14-dnevno slow log spremljanje,
- analyzer:
scripts/analyze-http-performance.php
Analyzer zna:
- p50
- p95
- p99
- max
- total time
- count
- 4xx
- 5xx
- 499
- rotated logs
- gzip logs
--since--until- coverage checking
M12 ✅ COMPLETE
13. M12.5 — Vector / Similar-AI incident
Odkrili smo konkretno težavo:
Skinbase je poslal Qdrantu:
limit = 121
Qdrant pa dovoljuje največ:
100
Gateway je nato napačno preslikoval Qdrant 422 v 502, kar je odpiralo circuit breaker.
M12.5A
Na Skinbase strani smo clampali similarity limit:
max 99 + exclusion = max 100
M12.5B
Gateway smo popravili:
- Qdrant 4xx ostane 4xx,
- Qdrant 5xx/transport → 502,
- sanitized error details.
Incident je bil nato zaprt.
M12.5 ✅ COMPLETE
Vector incident ✅ CLOSED
14. M12.6 — Analyzer izboljšave
Analyzer smo nadgradili za:
- rotated loge,
.gz,- exact status,
- status classes,
--since,--until,- coverage.
M12.6 ✅ COMPLETE
15. M13 — X-Accel artwork download
Velik performance win.
Prej je Laravel/PHP dejansko serviral datoteko.
Sedaj:
/download/artwork/{id}
Laravel naredi authorization/path resolution, nato pa nginx prevzame file transfer prek:
X-Accel-Redirect
Dodali smo tudi:
- internal nginx alias,
- range support,
- SHA preverjanje,
- rate limiting,
- Cloudflare real IP handling.
M13 ✅ COMPLETE
16. M14 — Scanner fast reject
Uvedli smo:
15-skinbase-scanner-fast-reject.conf
Nginx zdaj prestreže očitne probe še preden pridejo do PHP:
- WordPress
- phpMyAdmin
- PHPUnit
- secrets/config
- Docker
- Terraform
- private keys
- Swagger
- GraphQL scanner paths
- Spring actuator
- Grafana
- Elasticsearch
- itd.
Namerno nismo naredili blanket pravil, ki bi lahko blokirala legitimen Skinbase traffic.
M14 ✅ COMPLETE
17. M15 — Legacy download cleanup
M15A
Stari:
/download/{id}
je bil še vedno bombardiran z requesti, čeprav route ne obstaja.
Zdaj nginx vrne instant 404 brez PHP.
M15B
Artwork download route:
- public session samo kjer jo potrebujemo,
TrackOnlineVisitorse izloči,- invalid ID ne povzroča nepotrebnega Laravel overhead-a.
M15 ✅ COMPLETE
18. M16 — Legacy/scanner endpoints
Nginx fast reject smo dodali za:
/zoom.php
/dist/manifest.json
Pomembno:
/build/manifest.json
ostaja normalen Vite manifest.
M16 ✅ COMPLETE
19. M17 — Legacy cleanup
M17 je bil precej velik.
M17A — auth/admin scanner paths
Dodani exact/narrow rejects za:
/secure
/users/login
/signin
/sign-in
/signup
/console
/backoffice
/panel
/portal
/api/env
...
/wp/v2
Nismo blokirali legitimnih:
/reset-password
/auth
/account
/profile/*
/photo/*
/following/*
/livewire/update
...
M17B — legacy photo URLs
Implementiran:
LegacyArtworkPhotoController
- base62 decode,
- public/published artwork only,
- legacy photo path compatibility,
- direct 404 za neobstoječe datoteke,
- brez nepotrebnega visitor/session overhead-a.
M17B2 — legacy followers URL
Legacy:
/following/{id}/{slug?}
sedaj naredi 301 na canonical:
/@{username}/followers
Dodani:
- followers tab,
- pagination,
- canonical usernames,
- guest support.
M17C — ThumbnailService fix
Odstranili smo napačen:
orWhere('legacy_id', $id)
in ostali pri PK lookupu:
find($id)
Ker novi importer že ohranja legacy ID kot primary key.
M17 ✅ COMPLETE
20. M18 — Artwork detail optimization
To je trenutni glavni performance program.
M18A audit je pokazal, da /art/{id}/{slug} povzroča velik browser fan-out:
/art page
POST /api/art/{id}/view
GET navigation
GET similar-ai
GET rank
GET reactions
GET /page prefetch
...
Od tu naprej smo sistematično odstranjevali requeste.
21. M18B1 — Comment reaction N+1
Prej je frontend za vsak comment/reply posebej klical:
/api/comments/{id}/reactions
To je bil HTTP N+1.
Zdaj comments API že vsebuje reaction aggregate.
Rezultat:
automatic reaction GETs → praktično 0
Stari endpoint še vedno ostaja kompatibilen.
M18B1 ✅ COMPLETE
22. M18B2 — Duplicate artwork lookup
Odstranili smo drugi artwork lookup v public detail flowu.
Prej:
2 artwork lookupa
Po:
1 artwork lookup
Tudi Schema::hasTable() smo request-local memoizirali.
M18B2 ✅ COMPLETE
23. M18B3 — Lightweight neighbor prefetch
Prej je neighbor preload uporabljal skoraj full artwork page payload.
Dodali smo:
/api/artworks/{id}/page?prefetch=1
ki vrne samo:
id
title
slug
thumbs.md
thumbs.lg
Payload je padel približno:
~5776 B
→
~1034 B
SQL:
guest ~1
auth ~2
M18B3 ✅ COMPLETE
24. OPS-M18.1 — SSR process ownership
Odkrili smo race condition pri Inertia SSR.
Prej deploy:
stop SSR
nohup start SSR
kar je povzročalo:
EADDRINUSE
Zdaj je SSR pod:
Supervisor
Config:
/etc/supervisor/conf.d/skinbase-ssr.conf
Deploy samo naredi kontroliran supervisor restart.
OPS-M18.1 ✅ COMPLETE
25. M18B4 — Similar-AI defer
Similar-AI se prej avtomatsko sprožil pri vsakem artwork mountu.
Dodali smo:
IntersectionObserver
z:
rootMargin: 800px 0px
in JS-session registry:
- shared in-flight,
- reuse completed result,
- no duplicate request,
- retry after error,
- correct subscriber handling.
M18B4 ✅ COMPLETE
Kasnejši M18C pa je pokazal, da se request count ni zmanjšal toliko, kot smo pričakovali.
26. M18B5 — full /page audit
Pregledali smo možnost zmanjšanja full /page payload/queryjev.
Zaključek:
NO-OP
Ker full /page contract dejansko potrebuje:
- viewer
- stats
- categories
- maturity
- evolution
- file
- itd.
Ni bilo varne optimizacije brez spremembe contracta.
M18B5 ✅ COMPLETE — NO-OP
27. M18B6 — navigation SQL audit
Poskus optimizacije navigation queryja.
Ugotovili smo, da bi candidate izboljšava pomagala samo v zelo posebnem primeru z enim published artworkom.
Za normalen production workload ni imela smisla.
Original wrap-around semantics smo ohranili.
M18B6 ✅ COMPLETE — NO-OP
28. M18C — pravi production baseline
Zbrali smo približno:
26 h 47 min
79,402 requestov
Največji stroški:
/art/{id}/{slug}
count 24377
avg 0.615 s
total ~14999 s
Similar-AI:
count 2362
avg 1.707 s
total ~4032 s
Artwork page:
count 4508
avg 0.298 s
total ~1343 s
Navigation:
count 2713
avg 0.297 s
total ~805 s
M18C nam je dal zelo dobro osnovo za naslednje korake.
M18C ✅ COMPLETE
29. OPS-M18.2 — legacy CometChat
Našli smo:
/cometchat4/cometchat_receive.php
To je ostanek starega Skinbase/CometChat sistema.
SkinbaseNova ga ne uporablja.
M18C:
1831 requestov
1831 x 404
~0.365 s avg
~669 s PHP časa
Dodali smo exact nginx fast reject.
Sedaj:
404
request_time 0.000
no upstream
OPS-M18.2 ✅ COMPLETE
30. M18D — odstranitev neighbor prefetch requestov
Prej je:
/api/artworks/navigation/{id}
vrnil samo IDs/URLs.
Frontend je nato naredil še:
/page?prefetch=1
/page?prefetch=1
za oba soseda.
M18D je navigation response razširil z:
prev_preview
next_preview
ki vsebujeta:
id
title
slug
thumbs.md
thumbs.lg
Zato frontend ne potrebuje več dodatnih prefetch HTTP requestov.
Tipičen initial artwork:
PREJ
1 navigation
2 prefetch
ZDAJ
1 navigation
0 prefetch
Production/browser acceptance je prestal.
M18D ✅ COMPLETE
Production measurement boundary:
2026-08-28T18:44:04+02:00
Ta baseline trenutno še teče.
31. M18E — trenutno v delu
Codex trenutno dela na tem.
Cilj je odstraniti še standalone:
/api/artworks/navigation/{id}
iz normalnega browser flowa.
Ideja:
Initial page
Namesto:
GET /art/A
GET /api/artworks/navigation/A
želimo:
GET /art/A
SSR že vrne navigation payload.
Client navigation
Namesto:
GET /api/artworks/B/page
GET /api/artworks/navigation/B
želimo:
GET /api/artworks/B/page
Full /page response bo vseboval tudi navigation payload.
Standalone endpoint ostane fallback.
Če uspe:
initial artwork:
-1 HTTP request
vsak A → B:
-1 HTTP request
M18E 🟡 IN PROGRESS
Kaj še imamo v planu
Od tu naprej bi šel po podatkih, ne po vnaprej fiksnem seznamu.
M18F — M18D/M18E production validation
Najprej bomo izmerili učinek.
Za M18D imamo baseline:
START
2026-08-28T18:44:04+02:00
Primerjali bomo:
/page count
/navigation count
page/navigation ratio
total upstream time
p50/p95/p99
Po M18E bomo naredili nov boundary in enako meritev.
Glavni cilj:
navigation request count → skoraj 0 v normalnem UI flowu
M18G — Similar-AI druga faza
Similar-AI je še vedno drugi največji konkretni hotspot.
M18C:
2362 requestov
~4032 s total
avg 1.707 s
B4 ga je deferred, vendar ratio:
similar-ai / artwork detail
≈ 9.7 %
je bil skoraj isti kot prej (~10 %).
Zato moramo raziskati:
- zakaj
IntersectionObserverpraktično vedno triggera, - ali je sekcija preblizu viewporta,
- ali
rootMargin=800pxpovzroča skoraj instant load, - ali je smiselno AI recommendations loadati šele po dejanskem scrollu,
- ali uporabnik sploh vidi sekcijo,
- ali lahko rezultat reuseamo dlje v client sessionu.
Pomembno: ne bomo slepo spreminjali TTL-jev, breakerja ali Qdrant nastavitev.
M18H — artwork /art SSR cost
Po odstranitvi browser fan-outa ostane največji posamezni strošek:
/art/{id}/{slug}
M18C:
count 24377
avg ~615 ms
p95 ~1.11 s
p99 ~2.38 s
Takrat bomo naredili bolj natančen query/profile audit samega SSR requesta:
- relations,
- duplicate model serialization,
- avatar/profile lookup,
- categories,
- stats,
- metadata,
- SEO,
- props,
- Inertia serialization.
Cilj bo zmanjšati:
~0.615 s
brez spreminjanja funkcionalnosti.
M18I — view tracking
Trenutno imamo:
POST /api/art/{id}/view
M18C:
2715 requestov
avg ~390 ms
total ~1060 s
To je precejšen strošek za nekaj, kar je sekundarna funkcija.
Možne smeri:
- batch/deferred write,
- cheap queue dispatch,
- Redis counter + async persist,
- bolj minimalen middleware stack.
Vendar bomo pred tem preverili semantics, da ne pokvarimo unique view counting.
M18J — rank endpoint
M18C:
/api/rank/category/{id}
count 2444
avg ~379 ms
total ~927 s
To je naslednji očiten artwork fan-out kandidat.
Preverili bomo:
- ali se rank lahko doda v že obstoječ artwork response,
- ali se lahko request defera,
- ali je rank nujen na initial paint,
- cache hit/miss rate,
- ali je mogoče odstraniti standalone HTTP request.
M18K — comments endpoint
M18B1 je odstranil reaction N+1, vendar še vedno imamo:
/api/artworks/{id}/comments
M18C:
988 requestov
avg ~312 ms
Če bo po artwork optimizacijah še relevanten, pogledamo:
- lazy loading,
- payload size,
- pagination,
- avatar/profile serialization,
- relation queryje.
M19 — profile pages
M18C je pokazal tudi precejšen strošek:
/@{user}
count ~2061
avg ~648 ms
total ~1335 s
in:
/@{user}/gallery
~969 requestov
avg ~623 ms
Ko zaključimo artwork flow, je profil verjetno naslednji večji frontend/SSR kandidat.
M20 — homepage / discover
Potencialni naslednji kandidati:
/
discover/fresh
discover/trending
discover/rising
Trenutno niso kritični kot artwork, ampak imajo dovolj prometa, da se bodo prihranki poznali.
M21 — remaining legacy traffic cleanup
Performance log nam še vedno kaže stare/scanner URL-je.
Primeri:
/cometchat4/*
old downloads
wp probes
legacy PHP paths
old profiles
scanner APIs
Pristop ostaja isti:
dokazano ne obstaja
+
ni legitimne funkcije
+
veliko prometa
=
exact nginx fast reject
Nikoli blanket reject brez audita.
M22 — final infrastructure re-audit
Ko app-level optimizacije zaključimo:
- PHP-FPM saturation,
- CPU,
- MySQL latency,
- Redis latency,
- queue latency,
- nginx timings,
- slow requests,
- 5xx,
- 499,
- SSR health.
Šele če podatki pokažejo potrebo, bi razmišljali o spremembah workerjev ali infrastrukture.
Trenutna slika
Če to skrčimo na status:
M1–M17 ✅ COMPLETE
M18A ✅ audit
M18B1 ✅ reactions HTTP N+1
M18B2 ✅ duplicate artwork lookup
M18B3 ✅ lightweight prefetch
OPS-M18.1 ✅ Supervisor SSR
M18B4 ✅ deferred Similar-AI
M18B5 ✅ audit / no-op
M18B6 ✅ audit / no-op
M18C ✅ production baseline
OPS-M18.2 ✅ legacy CometChat nginx reject
M18D ✅ remove neighbor prefetch HTTP
M18E ✅ collapse navigation HTTP request
M18F ✅ production measurement
M18G ✅ Similar-AI phase 2
NEXT:
M18H artwork SSR optimization
M18I view tracking
M18J rank request
M18K comments
M19 profiles
M20 discover/home
M21 remaining legacy traffic
M22 final infra re-audit
Največja sprememba v celotnem projektu je, da smo začeli z običajnim “optimiziraj PHP/MySQL” pristopom, zdaj pa smo prišli do precej bolj učinkovitega modela: iz production telemetry identificiramo konkretne stroške, odstranimo nepotrebne HTTP requeste in Laravel bootstrape, nato rezultat ponovno izmerimo. Tako imamo pri skoraj vsakem koraku dokazljiv before/after.