gora.
Jusmila — moto-dalių katalogas Lietuvoje

Tech stekas

Turborepo monorepo, NestJS API, Next.js vitrina, Vite admin skydelis, chrome-devtools MCP skreperis.

~4 min skaityti · 796 žodžių

TL;DR

Turborepo monorepo su trimis programomis: API (NestJS + TypeORM + PostgreSQL 16 + Redis + Socket.IO), vieša vitrina (Next.js 14 + next-intl + TanStack Query), admin skydelis (Vite 6 + React 18 + Leaflet). Katalogo skreipingas — chrome-devtools MCP vietoj Puppeteer. Hostingas — atskiras ARM64 VPS.

Stekas ir architektūra

Monorepo

Turborepo surenka tris programas ir bendrus paketus:

auto-parts/
├── apps/
│   ├── api/        NestJS — REST + WebSocket
│   ├── web/        Next.js — vieša vitrina
│   └── admin/      Vite + React SPA — vidinis admin skydelis
├── packages/
│   ├── shared/     bendri DTO tipai
│   └── ui/         shared React komponentai (skirti admin)
├── scraper/        chrome-devtools MCP skreperis
└── deploy/         docker-compose, nginx konfigūracijos

Turborepo suteikia surinkimo cache (CI surenka tik pakeistą programą), turbo dev paleidžia visas tris lygiagrečiai lokalų vystymą.

API (NestJS)

NestJS 10 su TypeORM:

  • Autentifikacija: @nestjs/jwt + @nestjs/passport + bcrypt. Cookie pagrindu admin skydeliui, Bearer-tokenai būsimoms integracijoms.
  • Saugykla: PostgreSQL 16 per TypeORM. Pagrindiniai entity — Product, Category, Fitment, Order, OrderItem, Customer, DeliveryZone, Inventory, Supplier.
  • Cache: Redis per @nestjs/cache-manager + @keyv/redis. Kešuojamas filtruotas katalogas, fitment lentelės, geo susiejimai.
  • Real-time: @nestjs/platform-socket.io su @socket.io/redis-adapter — horizontalus mastelio keitimas, likučių sinchronizacija tarp admin skydelio ir vitrinos be perkrovimo.
  • Dokumentacija: @nestjs/swagger generuoja OpenAPI specifikaciją /api/docs adresu.
  • Apsauga: @nestjs/throttler rate-limiting užtikrinimui (ypač paieškos endpointuose), globalūs guards JWT ir rolių patikrai.

Vitrina (Next.js)

Next.js 14 su App Router. Pagrindiniai moduliai:

  • next-intl — daugiakalbiškumas (LT / RU / EN). Kiekviena kalba — atskiras URL prefiksas (/lt, /ru, /en), statiškai renderinama SEO tikslais.
  • TanStack Query (React Query) — serverio cache katalogui, krepšeliui, užsakymų būsenoms. Refetch lango fokusavimo metu, atnaujinimas per WebSocket invalidaciją.
  • Framer Motion — perėjimo tarp būsenų animacijos (kortelės įkrovimas, pridėjimas į krepšelį).
  • Zustand — kliento pusės būsena krepšeliui ir katalogo filtrams.
  • Tailwind CSS v4 — stilizavimas, be atskiros dizaino sistemos; komponentai rašomi vietoje.

Katalogas renderinamas mišriu režimu: kategorijų sąrašai — statiškai (ISR), prekių kortelės — serveryje su invalidacija pagal taimerį arba įvykį iš admin skydelio.

Admin skydelis (Vite SPA)

Vite 6 + React 18. Sunki SPA — daug ekranų, dažni perpiešimai, todėl Vite režimas suteikia greitą hot-reload be vėlinimų, skirtingai nei Next.js dev surinkimas.

  • Leaflet — Lietuvos žemėlapiai pristatymo zonoms. Naudojama be išorinių API (OpenStreetMap kaladėlės).
  • jsPDF + jspdf-autotable — sąskaitų ir ataskaitų eksportas tiesiai naršyklėje, be serverinio rendering.
  • react-quill-new — rich-text prekių aprašymams (HTML su paveikslėlių palaikymu).
  • rrweb-player — integruotas grotuvas session replay iš klientų skundų peržiūrai.
  • Recharts — analitikos grafikai (pardavimai, konversija).
  • react-router-dom 7 — kliento pusės maršrutizavimas, file-based nenaudojama.
  • Zustand — bendras store, be Redux.

Autentifikacija — bendra su API per JWT + cookie admin-* subdomene (arba basic-auth visiškai uždariems endpointams).

Skreperis

Atskiras scraper/ aplankas su duomenų importo skriptais. Požiūris — chrome-devtools MCP, o ne Puppeteer ar Playwright:

scraper/
├── README.md
├── scripts/
│   ├── import-mototex.ts
│   ├── import-anjese.ts
│   └── ...
└── data/         tarpinių rezultatų cache

MCP (Model Context Protocol) paleidžia realią naršyklę ir valdo ją iš Node proceso. Šaltinio svetainės požiūriu — tai įprastas vartotojas Chrome naršyklėje, todėl veikia svetainėse su agresyvia anti-bot apsauga.

Importo ciklas: atidaryti katalogo sąrašą → pereiti per puslapius → kiekvienoje kortelėje ištraukti artikulą, kainas, nuotraukas, fitment lentelę → normalizuoti → siųsti į API → API sukuria arba atnaujina prekę. Progresas keliauja į admin skydelį per WebSocket, operatorius mato importo eigą realiu laiku.

Hostingas

  • ARM64 VPS. Atskiras serveris, vartotojas parts. ARM pasirinktas dėl pigumo ir mažesnio energijos suvartojimo — katalogui be heavy-compute tai nėra kritinė problema.
  • nginx — reverse-proxy, TLS terminatorius, statika. Virtualūs hostai www vitrinai ir admin skydeliui skirtinguose subdomenuose.
  • Docker compose — visi servisai (api, web, admin, postgres, redis) viename faile. Deploy — docker compose pull && docker compose up -d.
  • GitHub Actions — CI: lint, type-check, build → push image į GHCR. Smart path filtras perrenka tik pakeistas programas.

Kriptomokėjimai

API yra prijungta bitcoinjs-lib ir bip32 — tai infrastruktūra kriptomokėjimų priėmimui (BTC, ETH per child-raktus). Adresų derivacija BIP32: vienas master-key platformai, child-adresai kiekvienam užsakymui — tai leidžia sekti įeinančias transakcijas neatskleidžiant master-key.

Tai kol kas pasirenkamas variantas vitrinoje, bet architektūra yra; rusakalbiam segmentui Lietuvoje tai gali tapti atsiskaitymų kanalu, kai euro įsigyjimas yra nepatogus.

Ką perrašyčiau

Naujoje iteracijoje:

  • Kainų atestavimas. Šiuo metu kainoraščiai importuojami kaip yra. Galima pridėti normalizavimo sluoksnį su istorija: „ši detalė pas tiekėją X kainavo Y, dabar Z, skirtumas 30%, gal pakišo padirbinį?“
  • CDN nuotraukoms. Šiuo metu paveikslėliai eina per nginx iš disko. Augant katalogui — vertėtų perjungti į S3/R2 + CDN.
  • Pilnatekstė paieška. TypeORM LIKE ištveria 10 000 SKU, bet esant 50 000+ reikia Postgres FTS arba Meilisearch.

Šiuo metu platforma veikia produkcijoje, užsakymai eina, katalogo importas automatizuotas. Tolimesnės iteracijos priklauso nuo asortimento ir srauto augimo.