Case study
Sadova Photographer — Next.js Marketing Platform
A commercial portfolio site built for lead generation: fast galleries, service landing pages, locations map, gift certificates, SEO structure, GA4 consent-mode analytics, and automated deploy.

Overview
Project overview
Not a simple “business card” — a marketing platform for a photographer in Lviv. Built for performance on large galleries, SEO-friendly structure, privacy-aware analytics, and easy updates via automated deploy.
ROLE
Full Stack Engineer
FOCUS
- Fast galleries at scale
- SEO structure + schema.org
- Map experience (lazy loaded)
- Privacy-aware analytics (consent mode)
- Automated deploy via GitHub webhook
Story
Problem → Solution → Outcome
PROBLEM
A photo portfolio must stay fast even with lots of media, while still being SEO-friendly and conversion-focused (services, promos, certificates, and easy contact).
SOLUTION
Implemented a “preview → original on demand” gallery pipeline with server-side thumbnails, structured SEO pages for services/promos, a lazy-loaded WebGL map, consent-gated GA4 analytics, and an automated webhook deploy flow.
OUTCOME
A premium, SEO-friendly marketing site that loads fast with large galleries, supports seasonal promo pages, and reliably turns visits into leads.
Highlights
What we built
Key systems shipped end-to-end — designed for reliability, conversion, and scale.
Fast galleries at scale
Pages load with lightweight previews, while full-resolution images are opened only when a user actually clicks.
- Thumbnails generated via Next.js API + sharp.
- Infinite scroll + lightbox for original assets.
- Categories sourced from public/photos/* without code changes.
SEO structure that ranks
Service pages, promo landings, and certificates designed with canonical/hreflang and rich schema markup.
- JSON‑LD types: WebPage, Organization, ContactPage, Service, Product, BreadcrumbList, FAQPage.
- Robots rules and sitemap.xml for predictable indexing.
Lazy-loaded locations map
A smooth WebGL map experience without hurting the first screen.
- MapLibre GL loaded via dynamic import + IntersectionObserver.
- Custom popups with a “route” CTA.
Analytics with privacy controls
GA4 runs in Consent Mode: suppressed before consent, enabled after — plus Web Vitals tracking.
- Custom events: scroll depth, engagement time, contact/outbound clicks.
- PII-safe filters: strips emails/phones from payloads.
Automated deploy + easy updates
A signed GitHub webhook triggers build and restart, while content can be updated by adding photos/pages without rebuilding the whole system by hand.
- x-hub-signature-256 verification before running deploy.sh.
- PM2-managed process with predictable restarts.
Challenges
Technical challenges
The hard parts — and the solutions that made the system stable.
Results
Impact
Measured outcomes and operational wins.
Fast load times on media-heavy pages thanks to server-side thumbnails and on-demand originals.
SEO-friendly structure with rich schema markup for services, promos, and certificates.
Privacy-aware analytics with consent gating and Web Vitals tracking.
Simplified maintenance via signed webhook deploy and PM2 restarts.
Stack
Tech stack used
Tools and patterns used on this build.
Frontend
- Next.js 16 (Pages Router)
- React 19
- TypeScript
- SCSS Modules
Images
- Next.js API routes
- sharp (thumbnail generation)
- FsLightbox
Maps
- MapLibre GL
- Dynamic import + IntersectionObserver
- Custom popups + route link
SEO
- Canonical + hreflang
- OG/Twitter
- JSON‑LD (schema.org)
- robots.txt + sitemap.xml
Analytics
- GA4
- Consent Mode
- Web Vitals to GA4
- Custom events (PII-safe)
Ops
- PM2
- GitHub webhook deploy
- x-hub-signature-256 verification
Metrics
Impact metrics
Gallery pipeline
2preview → original
Schema types
7JSON‑LD blocks
Deploy
1signed webhook
Next
Next case study
Keep browsing the system.
KLATS — Four Everyday Sounds Become a Beat
A mobile app that records four sounds from whatever is around you — a mug, a clap, keys, a voice — gives them musical roles and renders a finished beat with a vertical video. Analysis, arrangement and encoding all happen on the phone.