Konturas.lt
LTEN
← Visi darbai

Rezervacijų platforma · kalendorius · serverinis sekimas

Vila Valentino

Privati vila Ukmergės rajone, prie Kliepšių ežero. Vietoj nuomos per Booking.com ar paprasto WordPress puslapio – sava rezervacijų sistema su prieinamumo kalendoriumi, geografine lokalizacija ir serveriniu konversijų sekimu.

2024–2026·Sukūrimas, dizainas, architektūra, palaikymas·Iteracinis·Privataus poilsio nuoma · tiesioginės rezervacijos
Aplankyti vilavalentino.lt
Vila Valentino — screenshot

TL;DR — kuo skiriasi

  • Savas prieinamumo kalendorius: mąsto naktimis, ne dienomis; pusiau atviras intervalas leidžia tą pačią dieną vienam svečiui išvykti, kitam atvykti
  • Deterministinė kainodara su įšaldytu pasiūlymo momentu – sezonai, savaitgalio ir darbo dienos naktys, paketai ir priedai apskaičiuojami centų tikslumu
  • iCal sinchronizacija su Airbnb ir Booking.com kas 10 min. + konfliktų aptikimas; persidengimą blokuoja Postgres GiST EXCLUDE apribojimas
  • Geografinis maršrutas: lietuviui rodoma LT, užsieniečiui – EN versija (Cloudflare šalies antraštė + MaxMind GeoLite2), su metiniu slapuku pakartotiniam apsilankymui
  • Serverinis konversijų sekimas (Meta CAPI + Google Ads OCI), atlaikantis Safari ITP, su sutikimo valdymu pagal Consent Mode v2

Situacija

Iššūkis

Vilai Valentino reikėjo tiesioginio rezervacijų kanalo, nepriklausomo nuo komisinių. Užklausos vyko telefonu ir per OTA platformas, kurios pasiima 15–20 % nuo kiekvieno apsistojimo ir laiko svečio duomenis pas save. Paprastas WordPress puslapis su rezervacijų įskiepiu šios problemos neišsprendžia: prieinamumą tektų vesti rankiniu būdu, o kalendorius nesusikalbėtų su Airbnb ar Booking.com – atsirastų dvigubo užsakymo rizika.


Sprendimas

Kaip priėjome

Pradėjome ne nuo WordPress temos, o nuo duomenų modelio: prieinamumas, kainodara ir rezervacijos užklausa vienoje Postgres bazėje. Next.js App Router su LT/EN next-intl lokalizacija, savas prieinamumo kalendorius, deterministinė kainodara su įšaldytais pasiūlymo momentais, iCal sinchronizacija su išorinėmis platformomis ir serverinis konversijų sekimas, atlaikantis Safari ITP. Užsakymo apmokėjimo lange nėra – tai užklausų modelis, kuriame savininkas patvirtina datas rankiniu būdu.


Rezultatas

Kas pasikeitė

Vila priima rezervacijos užklausas tiesiogiai, be komisinių, ir matoma paieškoje pagal mergvakario, bernvakario, šeimos poilsio bei vietos raktažodžius LT ir EN kalbomis. Prieinamumas suvestas į vieną tiesos šaltinį iš rankinių blokų ir Airbnb / Booking.com kalendorių, o reklamos konversijos pasiekia Meta ir Google ir tada, kai naršyklė sekimą apriboja.


Naratyvas

Kaip tai sukurta

01 / PRADŽIA

Pradžios taškas

Vila Valentino – privati vila Ukmergės rajone, Kliepšių kaime prie Kliepšių ežero, maždaug valandos kelio nuo Vilniaus, Kauno ir Panevėžio. Keturi miegamieji, iki dešimties suaugusiųjų, pirtis, kubilas, terasa, privatus tvenkinys. Svečiai užsisakydavo telefonu arba per OTA platformas. Kiekviena rezervacija per Booking.com ar Airbnb reiškė komisinį ir svetimą sąsają tarp savininko ir svečio. Tad nepradėjome nuo WordPress temos – pradėjome nuo duomenų modelio: kaip vienoje vietoje laikyti prieinamumą, kainą ir užklausą taip, kad vienas kitam neprieštarautų.

02 / POZICIJA

Kodėl ne Booking.com ir ne WordPress įskiepis

Augančiai nuomai abu keliai turi tą pačią silpną vietą. OTA platforma duoda srautą, bet ima procentą ir laiko klientų duomenis pas save – savininkas nemato, kas, iš kur ir kada domėjosi. WordPress su rezervacijų įskiepiu atrodo pigiau, bet prieinamumą tenka vesti rankiniu būdu, o įskiepio kalendorius nesusikalba su Airbnb – pakanka vieno praleisto bloko ir tas pats savaitgalis parduodamas du kartus. Vila Valentino šį etapą peržengė iš karto: visa logika sutelkta vienoje sistemoje – viena duomenų bazė, vienas tiesos šaltinis apie datą, kainą ir užklausą.

03 / KALENDORIUS

Prieinamumo kalendorius, mąstantis naktimis

Rezervacijos kalendorius sukurtas nuo nulio. Esminis sprendimas – jis skaičiuoja naktimis, ne dienomis: apsistojimas saugomas kaip pusiau atviras intervalas nuo atvykimo iki išvykimo, todėl tą pačią dieną vienas svečias gali išvykti ryte, o kitas atvykti po pietų, ir kalendorius nelaiko tos dienos užimta abiem. Tai industrijos standartas (Airbnb, Booking.com), kurio paprasti įskiepiai dažnai nesilaiko.

Prieinamumas kiekvienai datai suvedamas iš dviejų šaltinių: rankinių blokų, kuriuos savininkas pažymi administravimo pusėje, ir importuotų iCal įvykių iš išorinių platformų. Tą patį laiką naują rezervaciją galima priimti tik tada, kai nė vienas aktyvus blokas su intervalu nepersidengia. Atvykimo dieną galioja 15 val. Vilniaus laiko riba: po jos einamoji diena nebepasirenkama kaip atvykimo data – kad svečias nespėtų užsisakyti laiko, kurio jau nebėra.

04 / KAINODARA

Deterministinė kainodara su įšaldytu pasiūlymu

Kainą skaičiuoja deterministinė logika, ne spėjimas. Iš sezonų taisyklių ir savininko nustatytų išimčių apskaičiuojama kiekvienos nakties kaina: atskiros darbo dienos ir savaitgalio nakties įkainiai, pirmos nakties priemoka, savaitės (7 naktų) ir mėnesio (30 naktų) paketai bei pasirinkti priedai – pirtis, kubilas žiemą. Visos sumos saugomos eurų centais, be slankiojo kablelio paklaidų.

Pateikus užklausą, apskaičiuotas pasiūlymas įšaldomas kaip atskira momentinė kopija: net vėliau pakeitus sezono įkainį, svečiui rodyta kaina nepasikeičia. Tai užklausų modelis – apmokėjimo lange nėra; pasiūlymas suskaidomas į avansą ir likutį, o datas savininkas patvirtina rankiniu būdu.

05 / SINCHRONIZACIJA

iCal sinchronizacija ir konfliktų aptikimas

Vila skelbiama ne vien savo svetainėje – datos užimamos ir per Airbnb bei Booking.com. Kad tas pats savaitgalis nebūtų parduotas du kartus, foninis darbuotojas kas 10 minučių importuoja išorinių platformų iCal kalendorius, sulygina juos su esamais įrašais ir paženklina dingusius. Jei importas grįžta tuščias, o bazėje yra aktyvių įvykių, sistema nesendina visų įrašų iš karto – taip vienas sugedęs atsakymas neištrina viso kalendoriaus.

Po kiekvienos sinchronizacijos tikrinami persidengimai: jei rankinis blokas ir importuotas įvykis kertasi, fiksuojamas konflikto stebėjimas su audito pėdsaku. Galutinę dvigubo užsakymo apsaugą užtikrina pati duomenų bazė – Postgres GiST EXCLUDE apribojimas fiziškai neleidžia įrašyti dviejų persidengiančių rankinių blokų.

06 / GEO

Geografinis kalbos maršrutas

Lietuvis turi pamatyti lietuvišką versiją, užsienietis – anglišką, ir nė vienam nereikia jos ieškoti. Pagrindinis adresas veikia kaip maršruto sprendimas: pagal Cloudflare šalies antraštę ir MaxMind GeoLite2 nustatoma lankytojo šalis ir parenkama LT arba EN versija. Pasirinkimas įrašomas į metus galiojantį slapuką, todėl pakartotinis apsilankymas geolokacijos nebekartoja. Paieškos robotai (Googlebot ir kt.) visada nukreipiami į LT versiją, atitinkančią hreflang numatytąją kalbą. Lokalizaciją tvarko next-intl „as-needed“ režimu – lietuviškas turinys be kalbos prefikso, angliškas po /en.

07 / SEO

Indeksavimas ir ketinimo puslapiai

Vietoj vieno bendro puslapio vila turi atskirus puslapius pagal svečio ketinimą: sodyba mergvakariui, bernvakariui, šeimos poilsiui, kompanijai, prie ežero, su kubilu, Kalėdoms. Kiekvienas paruošiamas serveryje (SSR) su lietuviškomis meta žymomis ir JSON-LD LodgingBusiness struktūra, todėl Google iškart mato turinį, ne tuščią karkasą. Search Console duomenimis (90 d.) vila indeksuota daugiau nei 25 puslapiais LT ir EN kalbomis ir rikiuojasi pagal ne prekės ženklo raktažodžius – „sodyba mergvakariui“ ties 5–6 pozicija, „sodyba bernvakariui“ ties 7, vietos užklausos pagal Ukmergės rajoną. Tarptautiniai parodymai ateina ne tik iš Lietuvos, bet ir iš Jungtinės Karalystės, Latvijos bei kitų šalių – EN versija pasiekia užsienio svečią.

08 / INFRA

Infrastruktūra ir foniniai darbai

Vila sukasi mūsų prižiūrimuose serveriuose: atskiri konteineriai svetainei (web) ir foniniam darbuotojui (worker), Postgres 16 antrojo lygio duomenų bazė, Redis eilėms ir diegimas per Coolify ant Hostinger VPS. Foninis darbuotojas valdo tris eiles: el. paštą (užklausos pranešimas savininkui), kalendorių sinchronizaciją (iCal importas, konfliktų rekonciliacija) ir priežiūrą (pasenusių įrašų bei limitų valymas). Formą nuo šiukšlinimo saugo Cloudflare Turnstile ir užklausų ribojimas, o klaidas fiksuoja Sentry. Administravimo pusė (better-auth) leidžia savininkui peržiūrėti užklausas, blokuoti datas, valdyti sezonų kainodarą ir iCal šaltinius.


Sekimas

Sekimas – trys kanalai, atlaikantys naršyklės apribojimus

[ Tracking · Server-side ]

Per pastaruosius metus naršyklės apkarpė didelę dalį duomenų, kuriais remiasi reklamos. Iš pirmo žvilgsnio atrodo, kad jos konvertuoja prasčiau, nors realybėje dalis konversijų tiesiog nebefiksuojama. Vilos Valentino užklausos signalas siunčiamas ne vien iš naršyklės: pagrindiniai įvykiai keliauja iš serverio, su sutikimo valdymu ir geografiniu kontekstu, kad Meta ir Google tą patį įvykį suskaičiuotų vieną kartą.

Naršyklės analitika

GA4 · Consent Mode v2 · PostHog

  • GA4 puslapių ir įvykių sekimas; pagrindinė konversija – pateikta rezervacijos užklausa
  • Consent Mode v2: analitikos ir rinkodaros kanalai įsijungia tik gavus atitinkamą sutikimą
  • PostHog seansų įrašai ir piltuvėliai – įjungiami tik su analitikos sutikimu

Meta

Pixel naršyklėje + CAPI iš serverio

  • Naršyklės Pixel ir serverinis CAPI siunčia tą patį įvykį su bendru event ID
  • Dedublikacija pagal event ID – Meta nesuskaičiuoja vienos užklausos dukart
  • Geografinis praturtinimas (šalis, miestas); kontaktiniai duomenys paverčiami maišos kodu (hash) prieš siuntimą
  • Įvykis pasiekia Meta ir tada, kai naršyklę riboja Safari ITP

Google Ads

OCI / Enhanced Conversions

  • Click ID fiksavimas iš reklamos nuorodų: gclid, gbraid, wbraid
  • Serverinis konversijų perdavimas su maišos kodu paverstais kontaktiniais duomenimis
  • Sutikimu valdomas; veikia po naršyklės sekimo apribojimų

Trys kanalai, vienas event ID. Daugelyje svetainių sekimas vyksta tik naršyklėje ir tyli, kai ją apriboja Safari ITP – čia pirkimo signalas keliauja ir iš serverio, todėl optimizacija nelieka aklame lange.


Technika

Architektūra

Next.js App Router su serveriniu atvaizdavimu ir next-intl LT/EN lokalizacija. Drizzle ORM virš PostgreSQL 16 (antrojo lygio bazė): prieinamumas, rankiniai blokai, iCal įvykiai, sezonų taisyklės, kainų išimtys, kainodaros momentinės kopijos ir užklausos. Redis + BullMQ trims eilėms (el. paštas, kalendorių sinchronizacija, priežiūra). better-auth administravimo prieigai. Visa SEO/geo/sekimo kompetencija perimta per bendrus @abyss paketus. Diegimas per Docker + Coolify ant Hostinger VPS, atskiri web ir worker konteineriai.

Front-endNext.js App Router · React · SSR
Back-endNode.js · Drizzle ORM · TypeScript · Zod
DBPostgreSQL 16 (Tier 2) · GiST EXCLUDE apsauga
EilėsRedis · BullMQ (el. paštas · kalendorius · priežiūra)
Lokalizacijanext-intl (LT/EN, as-needed) · MaxMind GeoLite2
SekimasGA4 · Consent Mode v2 · Meta CAPI · Google Ads OCI · PostHog
SEOSSR · hreflang · sitemap · JSON-LD LodgingBusiness
SaugaCloudflare Turnstile · užklausų ribojimas · Sentry
Authbetter-auth (administravimas)
OpsDocker · Coolify · Hostinger VPS · web + worker
Next.js App Routernext-intl (LT/EN)Drizzle + PostgreSQL 16Redis + BullMQbetter-authMaxMind GeoLite2Meta CAPIGoogle Ads OCIGA4 + Consent Mode v2Cloudflare TurnstileJSON-LD LodgingBusinessDocker · Coolify · Hostinger VPS

Integracijos

Geolokalizacija ir kalbų maršrutas

Vietoj atskiro AI sluoksnio vila remiasi tiksliomis integracijomis. Geografinis maršrutas pagal Cloudflare šalies antraštę ir MaxMind GeoLite2 parenka LT arba EN versiją dar prieš pirmą piešinį, metinis slapukas įsimena pasirinkimą, o paieškos robotai nukreipiami į hreflang numatytąją LT versiją. Lokalizaciją tvarko next-intl „as-needed“ režimu. Visa ši kompetencija – sekimas, geolokacija, SEO, sauga – perimta per bendrus @abyss paketus, todėl ta pati patikrinta logika veikia ir kituose projektuose.


Iššūkiai

Ką teko išspręsti

01

Naktimis, ne dienomis

Rezervacija turi būti saugoma kaip pusiau atviras intervalas [atvykimas, išvykimas), kad išvykimo diena liktų laisva kitam atvykti. Paprasti įskiepiai laiko dieną „užimta arba laisva“ – todėl tos pačios dienos persidengimo netvarko ir praranda apyvartą.

02

Vienas prieinamumo tiesos šaltinis

Prieinamumą reikėjo suvesti iš rankinių blokų ir iCal įvykių (Airbnb, Booking.com) į vieną atsakymą be dublikatų. Skirtingų platformų kalendoriai atnaujinami nevienodu dažnumu – sulyginimas turi būti atsparus vėlavimui.

03

Tuščio importo apsauga

Jei išorinis kalendorius grįžta tuščias dėl tinklo klaidos, naivi logika paženklintų visus įrašus kaip dingusius ir atlaisvintų užimtas datas. Reikėjo apsaugos: tuščias atsakymas nesendina aktyvių įrašų iš karto.

04

Dvigubo užsakymo apsauga DB lygmenyje

Programos patikrinimo neužtenka – lygiagretūs įrašai gali prasprūsti. Persidengimą fiziškai blokuoja Postgres GiST EXCLUDE apribojimas, todėl dvi besikertančios rezervacijos negali atsidurti bazėje net teoriškai.

05

Įšaldytas kainos pasiūlymas

Sezono įkainis gali pasikeisti po to, kai svečias jau gavo pasiūlymą. Apskaičiuota kaina saugoma kaip momentinė kopija, susieta su užklausa, todėl vėlesni pakeitimai jau pateiktos sumos nebekeičia.

06

Sutikimo laiko žemėlapis

Naršyklės ir serveriniai įvykiai elgiasi skirtingai pagal Consent Mode v2 būseną. Reikėjo tiksliai apibrėžti, kuris įvykis išleidžiamas ir kokia forma iki sutikimo, kad nebūtų pažeistas reglamentas ir neprarasta konversija.

07

Atribucija po Safari ITP

Naršyklės Meta Pixel ir serverinis CAPI turi siųsti tą patį įvykį, ne du. Jei event ID arba kontekstas išsiskiria, Meta optimizuoja pagal iškreiptus duomenis. Dedublikacija per bendrą event ID sprendžia tai abiejuose – Meta ir Google – kanaluose.

08

Geo maršrutas prieš pirmą piešinį

Kalbos parinkimas turi įvykti kaip maršruto sprendimas serveryje, ne kaip vėlesnė naršyklės korekcija – kitaip robotai ir reklamos srautas pamatytų netinkamą versiją. Sprendimas priimamas pagal Cloudflare antraštę dar prieš atvaizduojant turinį.

09

Dvikryptė kalendoriaus sinchronizacija

Importuoti svetimų platformų datas – tik pusė darbo. Kad Airbnb ar Booking.com nepriimtų rezervacijos dienomis, kurias vila užėmė tiesiogiai, vilos užimtų datų informacija eksportuojama atgal kaip iCal srautas. Nuoroda apsaugota atšaukiamu parašu (HMAC) – ją galima bet kada nutraukti, o vidiniai duomenys lieka neatskleisti.


Privalumai

Kuo lenkia standartą

01Tiesioginis kanalas be komisinių

Užklausa ateina tiesiai pas savininką, ne per OTA platformą su 15–20 % mokesčiu. Svečio duomenys lieka vilos pusėje, ne tarpininko.

02Vienas prieinamumo tiesos šaltinis

Rankiniai blokai ir Airbnb / Booking.com kalendoriai suvesti į vieną atsakymą su automatine sinchronizacija ir konfliktų aptikimu.

03Dvigubo užsakymo apsauga pamate

Persidengimą blokuoja pati duomenų bazė per GiST EXCLUDE apribojimą, ne tik programos patikra. Tas pats laikas fiziškai negali būti parduotas du kartus.

04Kalendorius pagal industrijos standartą

Pusiau atviras nakties intervalas ir 15 val. atvykimo riba elgiasi kaip Airbnb ar Booking.com – be klaidų, kurias daro paprasti įskiepiai.

05Skaidri deterministinė kainodara

Sezonai, savaitgalio ir darbo dienos naktys, paketai ir priedai apskaičiuojami centų tikslumu, o pasiūlymas įšaldomas – svečiui rodyta kaina nepasikeičia.

06Atribucija po Safari ITP

Serverinis sekimas reiškia, kad Meta ir Google užklausos signalą gauna ir tada, kai naršyklė tyli. Reklamos optimizacija nelieka aklame lange.

07Lietuviškas SEO ir geo maršrutas

Ketinimo puslapiai (mergvakaris, bernvakaris, šeima) su SSR ir JSON-LD; lietuviui rodoma LT, užsieniečiui – EN, automatiškai pagal šalį.

08Duomenų nuosavybė ir prognozuojama kaina

Visi duomenys – savoje Postgres bazėje, be procento nuo apsistojimo. Mėnesinė serverio sąskaita nepriklauso nuo užsakymų skaičiaus.

09Sutikimu grįstas sekimas

Analitikos ir rinkodaros žymos įsijungia tik gavus sutikimą (Consent Mode v2), o kontaktiniai duomenys siunčiami tik maišos kodu. Privatumas įrašytas į sekimo pamatą, ne prilipdytas šone.


Palyginimas

Vila Valentino vs. standartas

MetrikaWordPress + rezervacijų įskiepisVila Valentino
Komisiniai už rezervacijąOTA 15–20 % arba įskiepio licencija0 % – tiesioginė užklausa
Prieinamumo sinchronizacijaRankinė arba atskiri kalendoriaiAutomatinis iCal importas + konfliktų aptikimas
Dvigubo užsakymo apsaugaTik įskiepio logikaPostgres GiST EXCLUDE (DB lygmuo)
KainodaraFiksuota arba rankinėDeterministinė: sezonai, paketai, priedai, įšaldytas pasiūlymas
LokalizacijaVertimo įskiepisnext-intl + geo maršrutas (Cloudflare / MaxMind)
Reklamos sekimas po Safari ITPTik naršyklės pikselisServerinis Meta CAPI + Google Ads OCI
Lietuviškas SEO matomumasĮskiepis + vienas bendras puslapisSSR + JSON-LD + ketinimo puslapiai
Klientų duomenų nuosavybėPriklauso platformai / įskiepiui100 % savoje Postgres bazėje

Pamatyti gyvai — Vila Valentino svetainė


Skaičiai

Rezultatai

Rezervacijų kanalas

Be komisinių

Tik telefonas / OTATiesioginė svetainė

Lokalizacijos aprėptis

2 kalbos

0 kalbųLT + EN su geo maršrutu

Paieškos matomumas

Search Console, 90 d.

OTA profilis25+ indeksuotų puslapių (LT + EN)

Ne prekės ženklo užklausos

Sava ketinimo puslapiuose

„mergvakaris“ ~5–6, „bernvakaris“ ~7 poz.

Prieinamumo šaltinis

Vienas tiesos šaltinis

Rankinis kalendoriusRankiniai blokai + Airbnb/Booking iCal

Reklamos matomumas po Safari ITP

Atribucija nelieka aklame lange

Dalinis (tik naršyklė)Pilnas (serverinis CAPI + OCI)

Dvigubo užsakymo rizika

Persidengimas negalimas

GalimaPostgres EXCLUDE apsauga

Tarptautinis pasiekiamumas

Search Console, 90 d.

LT + GBR, LVA, AUS parodymai

Konkretūs sprendimo receptai – prieinamumo intervalų logika, kainodaros formulė, iCal rekonciliacijos ir konfliktų aptikimo seka, event ID dedublikacijos schema – viešai nepateikiami. Rimtam užsakovui pristatomi atskirai.