Iurii RoguliaIurii Rogulia
AboutServicesPricingProjectsStackReviewsPhrasesBlog
Contact
Iurii ships.

Iurii Rogulia, senior full-stack software engineer. Professionally building software since 2001.

Think of a number
PricingQuality checklistPrivacy PolicyCookie Policy

Business

TMI Iurii Rogulia
VAT ID: FI29845875
DUNS: 368664211
Lappeenranta, Finland 🇫🇮

[email protected]
Back to projects

Iurii Builds: Pikkuna — E-commerce for Vinyl Curtains & PVC Products

October 12, 2024

International e-commerce platform with 30 locales, product configurators, AI chatbot, and fully automated order flow: Stripe → Zoho CRM → Airtable → Mailgun → PDF.

Live Demo

Stack

Next.jsReactTypeScript

Libraries

next-intlZodpdf-libPuppeteerStripe.jsBullMQ

Databases

Redis

Services

StripeZohoMailgunPostNordNetvisorVercelVercel BlobGoogle AnalyticsMeta CAPIAirtableUpstash

Topics

E-commercePaymentsShippingPDFPWACTOArchitectureSEOSchema.orgi18nPerformance

Key Results

  • Cut per-order processing from 30 minutes to under 2 minutes — no ops team hired
  • Launched sales in 32 countries with 13 currencies and correct per-market VAT
  • Serves every customer in their own language across 30 fully localized markets
  • Recovers ad-attribution lost to adblockers and iOS via server-side GA4 + Meta CAPI
Pikkuna — E-commerce for Vinyl Curtains & PVC Products

The Business Problem

Pikkuna is a Finnish manufacturer of vinyl curtains and PVC products with a loyal local customer base and, at the time we started, zero international presence. The decision to expand internationally made the complexity immediate: 32 countries, a different VAT rate for every EU market, 13 currencies, and customers who expect to read — and be billed — in their own language.

Off-the-shelf platforms were ruled out early. Shopify could not handle the product configurators the business required: custom dimensions, material choices, and mounting options that recalculate price in real time. More critically, every order was being processed by hand. Confirming payment, creating a deal in the CRM, generating an accounting entry, booking a PostNord shipment, producing a PDF invoice and emailing it to the customer — a 30-minute workflow, spread across four tools, repeated for every single order. That was manageable at a dozen orders a week. It would not survive a European launch.

The Solution

I built the entire platform from scratch: storefront, checkout, product configurators, and every backend integration. The central design decision was to treat the manual order workflow as the primary problem. Everything else — the i18n, the VAT logic, the configurators — was important, but the order flow was the thing that would determine whether the expansion actually worked operationally.

A single Stripe webhook enqueues the order into a BullMQ (Redis-backed) job queue the moment payment is confirmed. A worker processes each order sequentially — Zoho CRM deal, Airtable backup record, PostNord shipment, Netvisor accounting entry, PDF invoice, confirmation email — with automatic retries on failure. From payment to invoice in the customer's inbox: under two minutes, with no one touching it.

The i18n system covers 30 locales. Each country carries its own currency, VAT rate, and shipping zone, all updated automatically before each build from live exchange rate and VAT APIs. Checkout pricing is always accurate, and there are no runtime API calls in the critical purchase path. The product configurators handle custom dimensions and pricing in real time on the client side. A RAG-based AI chatbot handles multilingual support — that system is documented separately.

Results

Processing time dropped from 30 minutes to under 2 minutes per order. For a company expanding to 32 countries without hiring an operations team, that gap was the difference between scaling and drowning.

MetricValue
Languages30 fully localized
Markets32 countries, 13 currencies
Order automationFully automated (payment → invoice)
Analytics captureServer-side (GA4 + Meta CAPI)
API integrations30+ endpoints
Regions3 (Frankfurt, Stockholm, Cleveland)

Server-side tracking (GA4 + Meta CAPI) captures the conversions that adblockers and iOS hide from client-side tracking — recovering attribution that would otherwise be invisible.

Technical SEO

Selling across 30 languages and 32 countries means SEO is not an afterthought you bolt on later — it has to survive localization, server-side rendering, and a constantly changing product catalogue. I owned the full technical SEO stack for this build:

  • hreflang across 30 locales — every product, category, and content page declares its language and regional alternates correctly, so Google serves the Estonian buyer the Estonian page and the German buyer the German one
  • Server-rendered product and category pages via Next.js App Router — no SPA-style blind spots for crawlers, no client-side hydration race that hides product data from Googlebot
  • Localized JSON-LD Product schema — pricing, currency, availability, and reviews are emitted per locale, with the structured data surviving the i18n layer (the most common place schema breaks on multilingual sites)
  • BreadcrumbList and Organization schema site-wide; FAQ pages for the most-searched questions in each market
  • Auto-generated sitemap with locale alternates and lastModified driven by product data — no plugin, no external tool, just code that runs at build time
  • Core Web Vitals tuned for mobile — image optimization, font loading without layout shift, third-party scripts deferred or moved server-side (the GA4 + Meta CAPI architecture removed two blocking client scripts)
  • OG images per product and category so social shares render the actual product, not a generic site banner

The same patterns are now my default for every project — covered in the Technical SEO I Build Into Every Project write-up.

Under the Hood

For the technically curious, here is how the core pieces are built.

Order Flow Automation via Stripe Webhook

Stripe webhook enqueues the order for sequential processing by a BullMQ worker, which handles retries with exponential backoff (illustrative — simplified from the production implementation):

// src/app/api/stripe-webhook/route.ts
export async function POST(req: Request) {
  const event = stripe.webhooks.constructEvent(body, sig, secret);
 
  if (event.type === "checkout.session.completed") {
    const session = event.data.object;
 
    // Enqueue for sequential processing — the worker handles
    // Zoho, Airtable, PostNord, Netvisor, PDF, and email in order
    await orderQueue.add("process-order", { sessionId: session.id });
  }
 
  return new Response("Queued", { status: 200 });
}

The worker processes each order sequentially — Zoho CRM, Airtable, PostNord, Netvisor, PDF invoice, confirmation email, then server-side analytics (GA4 + Meta CAPI) — retrying failed steps with exponential backoff before falling back to manual inspection in the queue dashboard.

Internationalization with Auto-Updated VAT and Exchange Rates

A prebuild pipeline automatically updates VAT rates and exchange rates:

// scripts/update-vat-rates.js
async function updateVatRates() {
  const euCountries = ['AT', 'BE', 'BG', ...];
  const rates = {};
 
  for (const country of euCountries) {
    const res = await fetch(
      `https://apilayer.net/api/rate?country_code=${country}`
    );
    const data = await res.json();
    rates[country] = data.standard_rate;
  }
 
  await fs.writeFile('vat-rates.json', JSON.stringify(rates));
}
 
// next-intl.config.js (32 countries with unique settings)
const countries = {
  finland: {
    locale: 'fi', currency: 'EUR',
    vatRate: vatRates.FI,  // Auto-updated
    exchangeRate: 1,
    shippingZone: 'finland',
    vatName: 'ALV'
  },
  germany: {
    locale: 'de', currency: 'EUR',
    vatRate: vatRates.DE,
    exchangeRate: 1,
    shippingZone: 'eu',
    vatName: 'MwSt'
  },
  unitedKingdom: {
    locale: 'en', currency: 'GBP',
    vatRate: 0,  // Non-EU
    exchangeRate: exchangeRates.GBP,
    shippingZone: 'america_asia',
    customsUrl: 'https://...'  // Customs info
  },
  // ... 29 other countries
};

RAG System for AI Chatbot

Chatbot uses Upstash Vector for semantic search over knowledge base:

// src/lib/rag-chat.ts
export async function getRelevantContext(query: string) {
  // Generate embedding via OpenAI
  const embedding = await openai.embeddings.create({
    model: "text-embedding-3-large",
    input: query,
  });
 
  // Search similar documents in Upstash Vector
  const results = await vectorIndex.query({
    vector: embedding.data[0].embedding,
    topK: 5,
    includeMetadata: true,
  });
 
  // Return context for prompt
  return results.map((r) => r.metadata?.content).join("\n\n");
}
 
// API route with streaming
export async function POST(req: Request) {
  const { messages } = await req.json();
  const context = await getRelevantContext(messages.at(-1).content);
 
  const result = streamText({
    model: openai("gpt-4o-mini"),
    system: `Answer based on this context:\n${context}`,
    messages,
  });
 
  return result.toDataStreamResponse();
}

PDF Invoice Generation on Vercel Serverless

Using Puppeteer with @sparticuz/chromium for serverless-compatible generation:

// src/lib/generateInvoice.ts
import chromium from '@sparticuz/chromium';
import puppeteer from 'puppeteer-core';
 
export async function generateInvoicePDF(order: Order) {
  const browser = await puppeteer.launch({
    args: chromium.args,
    executablePath: await chromium.executablePath(),
    headless: chromium.headless,
  });
 
  const page = await browser.newPage();
 
  // Render React component to HTML
  const html = renderToStaticMarkup(
    <InvoiceTemplate order={order} />
  );
 
  await page.setContent(html);
  const pdf = await page.pdf({ format: 'A4' });
 
  await browser.close();
  return pdf;
}

Project Reviews

“

As COO, I worked closely with Iurii, who led our IT department with rare clarity and ownership.

Andrii 🇫🇮

COO, Suomen Pehmeä Ikkuna Oy (Pikkuna)

Topics

E-commerceArchitectureLeadershipCTO
“

I have worked together with Iurii Rogulia in company Suomen Pehmeä Ikkuna Oy, where he conducted IT development and support. Thanks to his expertise, all tasks were solved in time.

Basil A 🇫🇮

Head of Customer Support, Suomen Pehmeä Ikkuna Oy (Pikkuna)

Topics

E-commerceSalesCTO
“

As Head of Production I had the opportunity to work closely with Iurii during his time with our company.

David Nemchin 🇫🇮

Head of Production, Suomen Pehmeä Ikkuna Oy (Pikkuna)

Topics

E-commerceArchitectureCTO
“

Before Iurii, our company site was a static brochure nobody had touched in years — wrong prices, an outdated team page, no way for us to publish anything ourselves.

Elina Virtanen 🇫🇮

Marketing Manager, Suomen Pehmeä Ikkuna Oy (Pikkuna)

Topics

Business WebsiteCMSE-commerce
Iurii RoguliaAvailable

Need something similar?

I build custom solutions — from APIs to full products. Let's talk about your project.

View all projects

Related projects

pi-pi.ee — B2B E-commerce for Waterless Urinal Systems
pi-pi.ee — B2B E-commerce for Waterless Urinal Systems
January 17, 2026
pi-pi.ee — B2B E-commerce for Waterless Urinal Systems

i18n B2B e-commerce platform for waterless urinal products across 32 European countries with automated VAT handling, PDF invoicing, and CRM integration.

Stack

Next.jsReactTypeScriptTailwind CSS

Libraries

next-intlDaisyUIStripe SDKreact-pdf

Services

StripeVercelResendNotionGoogle Analytics

Topics

E-commerceB2Bi18nPDFSSRArchitectureSEOSchema.org
Pikkuna — i18n RAG AI System
Pikkuna — i18n RAG AI System
December 15, 2025
Pikkuna — i18n RAG AI System

RAG system on OpenAI and Upstash Vector with 30 language support. Includes streaming chatbot, hybrid search (semantic + keyword), AI ticket classifier, and

Stack

Next.jsReactTypeScript

Libraries

Vercel AI SDKnext-intlassistant-uiZod

Databases

Upstash VectorRedis

Services

OpenAIUpstashVercel

Topics

RAGAI Chatboti18nE-commerceCTO

Related posts

E-commerce Order Automation: Stripe + Invoice + Shipping Workflow
February 22, 2026· 10 min
E-commerce Order Automation: Stripe + Invoice + Shipping Workflow

E-commerce order automation that cut 160+ hours/month of manual work to zero: Stripe webhook to VAT invoice and tracking in under 2 minutes.

Stack

Next.jsTypeScriptNode.js

Libraries

BullMQ

Databases

Redis

Services

StripeZohoAirtablePostNordNetvisorMailgun

Topics

E-commerceAutomationWebhooksPayments
Next.js SaaS Checklist: Launch Production-Ready in 8 Weeks
January 19, 2026· 17 min
Next.js SaaS Checklist: Launch Production-Ready in 8 Weeks

40+ point production SaaS checklist: auth, Stripe billing, PostgreSQL, rate limiting, email, monitoring, and security — with honest 8-week build estimates.

Stack

Next.jsTypeScript

Libraries

Drizzle ORMBetter AuthBullMQZodReact Email

Databases

PostgreSQLRedis

Services

StripeVercelResendSentry

Topics

SaaSArchitectureAuth