Gentian Voca

02Side project2025 – 2026

LokalWeb

A website-as-a-service for Kosovo’s small businesses

Most small businesses in Kosovo exist only on Instagram or TikTok. The opening hours are in a story that expired last week. LokalWeb asks the owner five questions in Albanian and gives the business a website on its own subdomain, with a booking calendar if it needs one.

Role
Solo: product, design, full-stack
Status
Working prototype, built solo
Stack
Next.js, TypeScript, Supabase, Claude API, Vercel
Live
Landing page
from business description to website
5 steps
a brand brief, then the theme
2 model calls
per business, resolved in middleware
1 subdomain
Supabase schema with row-level security
18 migrations

The LokalWeb landing page: a headline in Albanian, industry cards and a call to build a site.

The landing page at 1440 pixels wide. The marketing page speaks English; the wizard behind it speaks Albanian.

The problem

Barbershops, restaurants, clinics, salons: most of Kosovo’s small businesses have an Instagram page and no website. Hours, services and prices live in posts and stories, and a customer who wants to book sends a message and waits. A proper website costs a designer, a developer and a few weeks; most owners have none of the three.

LokalWeb began as my second-year software engineering project at UMIB and kept growing into a product: a business describes itself in plain words, and a few minutes later it has a website on its own subdomain, in Albanian, with a booking system if the business takes appointments.

The flow

  1. Industry, city, and the one thing that makes the business different.
  2. A description in the owner’s words, and the services with price and duration.
  3. A layout for each section, or “let the AI decide” per section.
  4. A visual archetype: eight presets, custom colours, or AI.
  5. Tone and language. Then Generate.

Wizard step two: the business description and a list of services with price and duration, in Albanian.

Step two: services with price and duration.

Wizard step four: a grid of eight visual archetype presets with colour swatches.

Step four: eight visual archetypes, custom colours, or let the model choose.

Decisions

  • Two calls, not one. First a brand brief (Claude Haiku, temperature 0.3, a strict JSON schema: positioning, three defining traits, target customer, voice, cultural anchor). Then theme and content generation (Claude Sonnet) working from that brief. Separating strategy from execution made the output more consistent and much cheaper to iterate on.
  • Structured output only. The renderer composes sections from typed JSON payloads. No free text from a model reaches the page unparsed.
  • A tenant per subdomain. Next.js middleware reads the host header and rewrites a business subdomain to its tenant routes; the main domain serves the wizard and the dashboard.
  • Supabase Auth with row-level security. Businesses, profiles, services, bookings. Eighteen migrations, including one called rls_tightening, which is the honest name for a day spent fixing my own policies.
  • Booking as the upsell. Timezone-aware slot generation, a uniqueness constraint against double bookings, WhatsApp confirmations. Walk-in businesses get a contact call-to-action instead.
  • Albanian where the owner types. The wizard is written in Albanian, with examples in the way people actually describe their shops. The generated site follows the language chosen in step five. The dashboard is still a mix of Albanian and English, which is on the list.
  • A wizard harness. Fixtures of real business types run through the pipeline on demand, so a change in the prompts shows up as a visible difference in the output, not a feeling.

A generated website for a test car dealership, Voca Autosallon: a dark hero with the Albanian headline E di çka po blen and a contact button.

A generated site for a test business, a car dealership. The headline, “E di çka po blen” (you know what you are buying), was written by the model from the wizard input.

The same generated site, section Pse Te Ne: five cards describing SUVs, sedans, wagons, coupés and a kilometre guarantee, in Albanian.

The same site, further down. Structured sections composed from the brief. The clipped logo in the header of the first screenshot is the product's own bug, not the screenshot's. Uneven in places, which is exactly the work that remains.

The owner dashboard: site status, quick actions and recent bookings.

The owner’s dashboard, on a test business.

The bookings view: a list of appointments with time, customer and service.

Bookings, with WhatsApp confirmations on the way out.

Where it stands

The core flow works end to end: a barber can describe the shop and get a site on a subdomain with services and a booking calendar. The generated output is uneven, and it needs real product work on layouts and copy before a paying customer should see it.

Work and university both became full-time in 2026 and the scope kept growing, so active development is on hold. It is the most ambitious thing I have built alone, and the clearest lesson in scope I have had.

What I learned

  • Structured output is the only kind a renderer should trust.
  • Scope is a product decision, not a technical one.
  • Stopping while it still works beats letting it decay.