BrickMatch
Full-stack aplikace, která páruje vlastní LEGO dílky s katalogem stavebnic Rebrickable. Ukáže vám, ke kterým setům máte nejblíže a které dílky vám do jejich dokončení scházejí. Jádrem aplikace je vyhledávací matching engine postavený na efektivní databázové indexaci a jediném agregovaném SQL dotazu, namísto pomalého procházení jednotlivých položek nebo nespolehlivého rozpoznávání obrázků pomocí AI.
- Next.js
- NestJS
- TypeScript
- Drizzle ORM
- Neon Postgres
- Zod
- pnpm workspaces
- TanStack Query
- nuqs
- Tailwind CSS
- shadcn/ui
- Vitest
- Jest
Náhled projektu
Kontext
LEGO je moje osobní záležitost. Často se mi stávalo, že jsem doma našel staré kostky nebo koupil náhodnou směs dílků, ale neměl jsem přehled, co z nich vlastně dokážu postavit. Dostupné nástroje buď spoléhají na rozpoznávání obrazu pomocí AI, které je u barev a specifických dílků velmi nespolehlivé, nebo nedokážou odpovědět na tu nejjednodušší otázku: které stavebnici jsem s dostupnými dílky nejblíže. Chtěl jsem vytvořit robustní vyhledávací jádro nad rozsáhlým reálným datasetem, spíše než jen postavit další jednoduchou CRUD aplikaci s nálepkou AI.
Technický přístup
- API v NestJS a frontend v Next.js provozované jako samostatně nasaditelné služby v pnpm monorepu, sdílející společný balíček se schématy Zod pro typovou bezpečnost a validaci dat.
- PostgreSQL B-tree index nad dvojicí (part_num, color_id) efektivně omezí prohledávaný katalog pouze na reálné kandidáty ještě před samotným výpočtem shody.
- Výpočet procentuální shody pro všechny potenciální stavebnice v rámci jediného seskupeného SQL dotazu s klauzulí HAVING namísto postupného dotazování pro každého kandidáta zvlášť.
- Katalogová data se do databáze importují předem z datových exportů Rebrickable. Backend tak při zpracování požadavků nemusí komunikovat s API třetích stran. Obrázky dílků a setů se načítají na straně klienta přímo z CDN sítě Rebrickable.
- JWT je bezpečně předáván prostřednictvím httpOnly cookie a na straně API validován pomocí Nest Passport. Frontend k tokenu nemá přímý přístup a stav přihlášení odvozuje z požadavku na endpoint /me prostřednictvím TanStack Query.
- Správa serverového stavu výhradně pomocí TanStack Query. Stav filtrů v URL adrese (témata, minimální shoda) je synchronizován pomocí knihovny nuqs.
Výzvy
- Služba Rebrickable ukládá dílky minifigurek v oddělené struktuře (grafu) namísto přímého inventáře dané stavebnice. Tento problém jsem vyřešil už ve fázi importu denormalizací a rozbalením všech částí minifigurek přímo do mateřského setu.
- Platformy BrickLink a Rebrickable používají odlišné interní identifikátory pro dílky a barvy, přičemž neexistuje žádné ucelené mapování. Místo náročné údržby vlastní převodní tabulky generuji exporty ve formátu Rebrickable CSV a samotný převod na formát BrickLink XML deleguji na osvědčený externí nástroj Rebrickable.
- Nalezení optimální prahové hodnoty pro minimální procento shody, která by fungovala konzistentně pro stavebnice různých velikostí – od drobných setů s desítkami dílků až po obří modely s tisíci kostkami.
- Návrh efektivního stránkování pro neustále se rozrůstající sbírku uživatele při zachování přímého načítání malých statických číselníků (barvy, témata) bez zbytečné režie.
Co jsem se naučil
- U rozsáhlých katalogů patří nejtěžší práce do databázového indexu a jediné SQL agregace. Cyklické procházení desítek tisíc záznamů v aplikačním kódu je jasným architektonickým prohřeškem (code smell).
- Komplexní vazby v katalogu, jako jsou dílky minifigurek, je nejlepší denormalizovat už při importu. Runtime vyhledávání pak zůstane jednoduchou a plochou operací nad dvojicí (part_num, color_id).
- Sdílení Zod schémata eliminuje riziko nesouladu (driftu) datových modelů mezi frontendem a backendem. Pro integraci plně postačila jednoduchá vlastní validační runda v NestJS – použití knihoven jako nestjs-zod by přineslo jen zbytečnou komplexitu.
- Nemá smysl vyvíjet a udržovat vlastní převodníky ID mezi různými platformami, pokud již existuje spolehlivé řešení přímo u zdroje. Generování CSV ve formátu Rebrickable se ukázalo jako podstatně jednodušší cesta s minimální režií.
- Stránkování je důležité produktové rozhodnutí. Zatímco neustále rostoucí uživatelské sbírky jej vyžadují, drobné statické číselníky (barvy, témata) je mnohem efektivnější stáhnout jednorázově a cachovat na klientovi.
Hlavní funkce
- Vyhledávací matching engine využívající databázové indexy nad katalogem s více než 20 000 stavebnicemi
- Sdílená Zod schémata pro stoprocentní typovou bezpečnost a validaci mezi frontendem a backendem v rámci pnpm workspace
- Bezpečná JWT autentizace předávaná přes httpOnly cookie s dodatečným potvrzením hesla u citlivých akcí
- Export chybějících dílků do CSV (formát Rebrickable) a BrickLink XML prostřednictvím oficiálního převodníku
- Předpřipravení (denormalizace) dílků z minifigurek přímo do inventáře stavebnic při importu, což zrychluje vyhledávání
- Atomická operace „postavení stavebnice“, která odečte použité dílky z vaší sbírky pouze při stoprocentním dokončení setu
Další projekt
TextForge
Nástroj pro okamžitý převod a formátování textu s podporou AI, odvozováním schémat a prémiovým přístupem přes Stripe.