ტექნიკური კეისი: Digital Craft-ის პორტფოლიო
ჩვენ digital-craft-tbilisi.site-ის შემუშავებას მივუდექით, როგორც პროდუქტს, სადაც თითოეული ტექნიკური გადაწყვეტა დასაბუთებულია, კოდის თითოეული ბაიტი — გამართლებული, ხოლო საბოლოო არქიტექტურა — მასშტაბირებადი ხარჯების ზრდის გარეშე.
ამ კეისში ჩვენ სისტემას შიგნიდან ვაანალიზებთ: კონცეფციიდან და სტეკის არჩევიდან კონკრეტულ ალგორითმებამდე, რომლებიც ახლა პროდაქშენზე მუშაობენ.
რატომ უარვყავით სტანდარტული CMS
პირველი კითხვა, რომელიც დასაწყისში დავსვით: სულ რატომ გვჭირდება რაიმეს ხელით წერა? WordPress ოცი წელია არსებობს, Tilda ამოცანას რამდენიმე საათში წყვეტს, Webflow ვიზუალურ კონტროლს ვერსტკაზე იძლევა. არგუმენტები საკუთარი გადაწყვეტის წინააღმდეგ აშკარაა.
არგუმენტები სასარგებლოდ უფრო ძლიერი აღმოჩნდა.
პირველი პრობლემა: სიჩქარე და ჭარბი კოდი
WordPress სტანდარტული ინსტალაციით გვერდს დინამიურად ქმნის თითოეული მოთხოვნისას: მოთხოვნა მონაცემთა ბაზასთან, PHP-ის შესრულება, HTML-ის შეგროვება, კლიენტთან გაგზავნა. აგრესიული კეშირებითაც კი Time To First Byte იშვიათად ეცემა 200–400 მს-ზე დაბლა. Tilda და მსგავსი კონსტრუქტორები სტატიკას ქმნიან, მაგრამ მასთან ერთად — ათეულ კილობაიტ გამოუყენებელ CSS-სა და JS-ს, ჩაშენებულ მრიცხველებს, გარე სერვისებთან მიმართვებს.
სააგენტოსთვის, რომელიც ტექნიკურ ექსპერტიზას ყიდის, საშუალო Core Web Vitals-ის მქონე საიტი — განმარტებაში წინააღმდეგობაა.
მეორე პრობლემა: მულტიენოვანობა პლაგინების გარეშე
ჩვენ ოთხ ბაზარზე ვმუშაობთ: ქართულენოვანი აუდიტორია საქართველოში, რუსულენოვანი დიასპორა, უკრაინული ბაზარი, ინგლისურენოვანი კლიენტები. თითოეული სეგმენტი მოითხოვს არა მარტო თარგმნილ ტექსტს, არამედ ტექნიკურად სწორ SEO-მარკირებას: სწორ hreflang თეგებს, რეგიონულ ვარიანტებს (ru-GE, ka-GE), კორექტულ x-default-სა და sitemap.xml-ში დაკავშირებულ ჩანაწერებს.
WPML ტიპის პლაგინები ამ ამოცანას ნაწილობრივ და ფულიანად წყვეტენ. ჩვენ გვჭირდებოდა სისტემა, სადაც მულტიენოვანობა — არ არის დამატება, არამედ არქიტექტურის ნაწილი პირველი დღიდან.
მესამე პრობლემა: შეზღუდული SEO და პლატფორმაზე დამოკიდებულება
ნებისმიერი SaaS-პლატფორმა შეზღუდვებს ადებს: URL სტრუქტურას, მეტათეგების გენერაციის მეთოდს, sitemap ფორმატს. ეს შეზღუდვები კრიტიკული არ არის პროექტების უმეტესობისთვის, მაგრამ მიუღებელია სააგენტოსთვის, რომლის კომპეტენცია — სწორედ ტექნიკური SEO-ა.
მიზნები, რომლებიც დავსახეთ
- TTFB რაც შეიძლება ნულთან ახლოს — გვერდი სტატიკური ფაილივით უნდა გაიცეს CDN-იდან.
- სრული კონტროლი SEO-მარკირებაზე პლატფორმის შეზღუდვების გარეშე.
- ნათიური მულტიენოვანობა არქიტექტურის დონეზე, არ პლაგინების.
- დამოუკიდებლობა ფასიანი CMS-ებისა და გამოწერებისაგან.
- მზადყოფნა AI-ძიებისთვის — ახალი რეალობისთვის, სადაც საიტები ინდექსირდება არა მხოლოდ საძიებო ბოტებით, არამედ ენობრივი მოდელებითაც.
ტექნიკური სტეკი და არქიტექტურის კონცეფცია
საიტის არქიტექტურა სამ კომპონენტზეა აგებული, რომელთაგან თითოეული მკაცრად საკუთარ პასუხისმგებლობის ზონას ფარავს.
Firebase, როგორც Headless CMS
Firebase Firestore ბაზის მონაცემებისა და მთელი კონტენტის სიმართლის წყაროს როლს ასრულებს. რედაქტორი მონაცემებთან მუშაობს კასტომური ადმინ-პანელის მეშვეობით, რომელიც პირდაპირ Firestore-ში წერს. ამავდროულად, Firebase კონტენტის გადაცემაში საბოლოო მომხმარებლისთვის არ მონაწილეობს — ის არსებობს მხოლოდ შეგროვებისა და მართვის ეტაპზე. ეს კლასიკური Headless-არქიტექტურაა: ბექენდი ფრონტენდისგან სრულად გამოყოფილია.
Python, როგორც სტატიკური გენერატორი
Python-სკრიპტი generate_site.py — საიტის კომპილატორია. ის Firestore-დან ყველა მონაცემს გადმოქაჩავს, Jinja2 შაბლონიზატორზე გაატარებს და მზა HTML-ფაილებს დისკზე ჩაწერს. შეგროვების დასრულების შემდეგ Python-ი სხვა აღარ სჭირდება: საიტი სტატიკური ფაილების ნაკრებად არსებობს.
Vanilla JS, როგორც SPA-ძრავი
კლიენტის მხარეს მუშაობს JavaScript-ძრავი სუფთა Vanilla JS-ზე — React, Vue ან Angular-ის გარეშე. ის History API-ის მეშვეობით გვერდებს შორის შეუფერხებელ ნავიგაციას უზრუნველყოფს, Intersection Observer-ის გავლით ანიმაციებს მართავს და ყოველი გადასვლის შემდეგ ინტერაქტიულ კომპონენტებს ინიციალიზებს.
კონცეფცია: შეგროვება ფრენის დროს, გაცემა სტატიკად
არქიტექტურის მთავარი პრინციპი: ყველა გამოთვლითი სამუშაო ერთხელ ხდება — შეგროვებისას. როდესაც კონტენტ-მენეჯერი deploy-ის ღილაკს დააჭერს, Python-სკრიპტი რამდენიმე წამში სრულ საიტს ქმნის: ყველა გვერდს ყველა ენაზე, sitemap-ს, llms-full.txt-ს, 404-გვერდს. შედეგი — სტატიკური ფაილების საქაღალდე, რომლის გავრცელება ნებისმიერ CDN-ზეა შესაძლებელი ნულოვანი სერვერული დატვირთვით.
WordPress-თან შედარება: 1000 ერთდროული ვიზიტორის დროს WordPress 1000 მოთხოვნას PHP-სთან და ბაზასთან ქმნის. ჩვენი არქიტექტურა იმავე 1000 ვიზიტორთან ქმნის 0 სერვერულ გამოთვლას — CDN ფაილს კეშიდან გასცემს.
ძირითადი გადაწყვეტილებები: ფენების მიხედვით ანალიზი
ჰიბრიდული არქიტექტურა: generate_site.py და Jinja2
შეგროვების სკრიპტი რამდენიმე თანმიმდევრული ეტაპით ეშვება.
პირველი ეტაპი — ინიციალიზაცია. სკრიპტი Firebase-ს სერვისული ანგარიშის მეშვეობით უკავშირდება, რომელიც FIREBASE_SERVICE_ACCOUNT გარემოს ცვლადად გადადის. გასაღებები რეპოზიტორიაში არ ინახება — ეს CI/CD პაიპლაინებთან მუშაობისას უსაფრთხოების სავალდებულო პირობაა.
მეორე ეტაპი — მონაცემების ჩატვირთვა. სკრიპტი Firestore-ის ყველა კოლექციას გადის: home, services, portfolio, blog, contact, carouselItems. მონაცემები ერთი ბლოკად იტვირთება მუშაობის დასაწყისში, API-სთან მოთხოვნების რაოდენობის მინიმიზაციისთვის.
მესამე ეტაპი — რენდერინგი. თითოეული კოლექციის თითოეული დოკუმენტისთვის სკრიპტი შესაბამის Jinja2-შაბლონს განსაზღვრავს და გვერდს მონაცემების ჩასმით რენდერს უკეთებს. შედეგი public/ დირექტორიაში იწერება გვერდის მომავალი URL-ის შესაბამის მისამართზე.
მეოთხე ეტაპი — სერვისული ფაილების გენერაცია: sitemap.xml, llms-full.txt.
ინტელექტუალური პარსინგი: [TOC] მარკერი
ერთ-ერთი არასტანდარტული ამოცანა — გრძელი სტატიებისთვის სარჩელის ავტომატური გენერაციაა. რედაქტორი სარჩელს ხელით არ ვერსტავს: უბრალოდ ტექსტის დასაწყისში [TOC] ხაზს ამატებს.
სკრიპტი ამ მარკერს პოულობს და lxml ბიბლიოთეკის მეშვეობით პარსინგს იწყებს. ალგორითმი შემდეგია: სტატიის HTML-შინაარსი ელემენტების ხეში იპარსება, სკრიპტი ხეს გადის და ყველა h2 და h3 თეგს ასაგროვებს, თითოეულ სათაურს id-ატრიბუტი ენიჭება მისი ტექსტური შინაარსის საფუძველზე (ტრანსლიტერირებული და გაწმენდილი), შემდეგ შეგროვებული სათაურებიდან ბმულების ჩადგმული სია იქმნება, რომელიც მარკერის ნაცვლად ჩასმება.
მნიშვნელოვანი დეტალი: id-ატრიბუტები ერთი და იმავე slugify() ფუნქციის მეშვეობით გენერირდება, რაც შეგროვებისას URL-ების გენერაციაშიც გამოიყენება — ეს კონფლიქტების არარსებობას და ქართული და რუსული სათაურებისთვის სარდლობის ბმულების სწორ მუშაობას უზრუნველყოფს.
ინტელექტუალური პარსინგი: [CAROUSEL:key] მარკერი
მარკერი [CAROUSEL:key] სტატიის ნებისმიერ ადგილას ინტერაქტიული კარუსელის ჩაშენების საშუალებას იძლევა. გასაღები Firestore-ში სლაიდების კოლექციის იდენტიფიკატორს შეესაბამება.
დამუშავებისას სკრიპტი სტატიის სხეულში მარკერს პოულობს, წინასწარ მიღებული მონაცემებიდან შესაბამის კარუსელის კოლექციას ტვირთავს, კარუსელის HTML-მარკირებას ცალკე შაბლონის მეშვეობით რენდერს უკეთებს და მარკერის ნაცვლად ჩასვამს. საბოლოო HTML სრულად მზა კომპონენტს შეიცავს — კარუსელის JavaScript-ძრავი მას გვერდის ჩატვირთვისას ინიციალიზებს.
კასტომური ტრანსლიტერაცია: slugify() ლოგიკა
ფუნქცია slugify() პარალელურად ორ ადგილას არის რეალიზებული: Python-სკრიპტში შეგროვებისას URL-ების გენერაციისთვის და Vanilla JS-ში კლიენტური როუტინგისთვის. ორივე ეგზემპლარი იდენტური ალგორითმით მუშაობს, რაც სერვერსა და ბრაუზერზე URL-ების კონსისტენტობას უზრუნველყოფს.
ალგორითმი ორმაგ ანბანის დეტექციაზეა აგებული:
- სკრიპტი ამოწმებს, შეიცავს თუ არა სტრიქონი Unicode დიაპაზონში
U+10D0–U+10FFსიმბოლოებს (ქართული მხედრული ანბანი). თუ კი — გამოიყენება კასტომური ტრანსლიტერაციის ცხრილი: თითოეული ქართული სიმბოლო ეროვნული რომანიზაციის სტანდარტების მიხედვით ლათინური ეკვივალენტით იცვლება. მაგალითად:შ → sh,ჩ → ch,ხ → kh,ჟ → zh,ჯ → j. - შემდეგ სკრიპტი კირიულის არსებობას ამოწმებს
U+0400–U+04FFდიაპაზონში. კირიულიtransliterateბიბლიოთეკის (Python) ან ჩაშენებული ცხრილის (JS) მეშვეობით ტრანსლიტერდება, უკრაინული სიმბოლოების ჩათვლით:ї → yi,є → ye,ґ → g. - ტრანსლიტერაციის შემდეგ ყველა სიმბოლო გარდა
a-z,0-9და დეფისებისა, იშლება. მრავლობითი დეფისები ერთში ითასმება, წამყვანი და კუდი დეფისები კვეცება.
შედეგი: URL სახის /ka/blog/saiti-mcire-biznesisat/ და /ru/blog/tekhnicheskoe-seo-dlya-biznesa/ პროცენტ-კოდირებული სტრიქონების ნაცვლად, რომლებიც ანალიტიკას ტეხენ და ბმულების კოპირებისას პრობლემებს ქმნიან.
SEO-ინჟინერია და AI-ready მიდგომა
translationGroupKey ლოგიკა
მულტიენოვანობა რეალიზებულია არა ინტერფეისის გადამრთველად, არამედ მონაცემთა ბაზის დონეზე კავშირად. Firestore-ში თითოეულ გვერდს translationGroupKey ველი აქვს — თვითნებური იდენტიფიკატორი, რომელიც ერთი მასალის თარგმანებს აერთიანებს. მაგალითად, ტექნიკური SEO-ს შესახებ სტატია ოთხ ენაზე ამ ველის ერთნაირ მნიშვნელობას ექნება: technical-seo-guide.
შეგროვებისას სკრიპტი თარგმანების რუკას ქმნის: თითოეული უნიკალური translationGroupKey-ისთვის ასეთი გასაღების მქონე ყველა გვერდის სია სახდება. შემდეგ თითოეული გვერდის გენერაციისას ეს სია ორი მიზნისთვის გამოიყენება: head-ში hreflang თეგების ჩასმა და sitemap.xml-ში ალტერნატიული URL-ების ჩანაწერების დამატება.
hreflang-ის ავტომატური გენერაცია
თითოეული გვერდისთვის, რომელსაც თარგმანები აქვს, სკრიპტი link rel="alternate" თეგების სრულ ნაკრებს ქმნის. რეგიონული კოდი (GE, RU, UA) Firestore-ში region ველში განისაზღვრება და ავტომატურად ემატება hreflang ატრიბუტის მნიშვნელობაში.
თეგი x-default Google-ს ეუბნება, რომელი ვერსია გამოჩნდეს მომხმარებლებისთვის ცხადი ენობრივი უპირატესობის გარეშე. სკრიპტი x-default-ს Firestore-ის ჩანაწერში isXDefault ფლაგით განსაზღვრავს. თუ ფლაგი ვერსიებიდან არცერთს არ ჰყავს, სკრიპტი ავტომატურად გვერდის ინგლისურ ვერსიაზე ანიჭებს x-default-ს.
საბოლოო hreflang ბლოკი ბლოგის სტატიისთვის ასე გამოიყურება:
<link rel="alternate" hreflang="ru-GE"
href="https://digital-craft-tbilisi.site/ru/services/razrabotka-saitov-tbilisi/" />
<link rel="alternate" hreflang="en-GE"
href="https://digital-craft-tbilisi.site/en/services/custom-web-development-tbilisi/" />
<link rel="alternate" hreflang="ka"
href="https://digital-craft-tbilisi.site/ka/services/veb-gverdebis-damzadeba-tbilisi/" />
<link rel="alternate" hreflang="uk"
href="https://digital-craft-tbilisi.site/uk/services/rozrobka-saitiv-tbilisi/" />
<link rel="alternate" hreflang="x-default"
href="https://digital-craft-tbilisi.site/en/services/custom-web-development-tbilisi/" />ეს მთელი ბლოკი ავტომატურად გენერირდება. რედაქტორი ერთ ველს ავსებს — translationGroupKey — დაკავშირებულ გვერდებში. ყველა დანარჩენს სისტემა მომდევნო შეგროვებისას თავად გააკეთებს.
დინამიური Sitemap lastModified-ით
ფაილი sitemap.xml ყოველ deploy-ზე თავიდან ასაგებს. სკრიპტი თითოეული Firestore-ის დოკუმენტიდან lastModified ველს იღებს და თეგში ათავსებს. ეს ნიშნავს, რომ საძიებო ბოტი ყოველთვის ხედავს ბოლო ცვლილების სწორ თარიღს — არა ბოლო deploy-ის თარიღს, არამედ კონკრეტული გვერდის რეალური განახლების თარიღს. პრიორიტეტი (priority) და ცვლილებების სიხშირე (changefreq) Firestore-ის ველებით თითოეული გვერდისთვის ინდივიდუალურად ხდება.
AI-ready ინფრასტრუქტურა: llms.txt და llms-full.txt
საძიებო ლანდშაფტი იცვლება. ინფორმაციული მოთხოვნების სულ უფრო დიდი ნაწილი ენობრივი მოდელებით — ChatGPT, Claude, Perplexity — მუშავდება, რომლებიც პასუხს საკუთარი ცოდნისა და მათთვის ხელმისაწვდომი მონაცემების საფუძველზე ქმნიან. ამ პასუხებში მოხვედრისთვის კლასიკური SEO საკმარისი არ არის: AI-აგენტებს სტრუქტურირებული აღწერა სჭირდებათ ისეთ ფორმატში, რომელსაც კითხვა შეუძლიათ.
ამისთვის არსებობს ფორმირებადი სტანდარტი llms.txt ან llms-full.txt. ჩვენ მისი მხარდაჭერა განვახორციელეთ.
llms-full.txt — მკაცრი მანქანის მიერ წაკითხვადი ფორმატი საიტის მთელი სტრუქტურით. გვერდები translationGroupKey-ის მიხედვით არის დაჯგუფებული: აგენტი ხედავს არა განცალკევებულ URL-ებს, არამედ ლოგიკურად დაკავშირებულ მასალების ჯგუფებს ენებისა და რეგიონების მითითებით. ენობრივი მოდელი, რომელიც ამ ფაილს მიმართავს, სააგენტოს საქმიანობის შესახებ სრულ წარმოდგენას იღებს.
ფაილი ყოველ შეგროვებისას სკრიპტის მიერ გენერირდება — საიტის აქტუალური სტრუქტურა AI-აგენტებისთვის ხელით განახლების გარეშე ყოველთვის ხელმისაწვდომია.
კასტომური CMS: Firebase Admin Panel
კონტენტის მართვა კასტომური Single Page Application-ის მეშვეობით ხდება, Vanilla JS-ზე Firebase-ის ბექენდით. ეს სრულფასოვანი CMS-ია მესამე მხარის პლატფორმებისა და ყოველთვიური გამოწერების გარეშე.
პანელი კონტენტის სრულ სასიცოცხლო ციკლს ფარავს:
- გვერდების შექმნა და რედაქტირება ყველა ოთხ ენობრივ ვერსიაში.
- მულტიენოვანი კავშირების მართვა
translationGroupKey-ის მეშვეობით. - SEO-ველების კონფიგურაცია:
seoTitle,metaDescription, OG-თეგები,isXDefault, რეგიონი, sitemap-ში პრიორიტეტი. - მედიაფაილების ატვირთვა Firebase Storage-ში საჯარო URL-ების ავტომატური მიღებით.
- კარუსელის სლაიდების მართვა: თანმიმდევრობა, გამოსახულებები, სათაურები, აღწერილობები.
- თვითნებური HTML/CSS/JS-ის ჩასმა თითოეული გვერდის ანიმირებული ფონისთვის.
Autofill from Article ფუნქცია
კარუსელის სლაიდის შექმნა კონტენტ-მენეჯერის ტიპური ამოცანაა ახალი სტატიის გამოქვეყნების შემდეგ. ავტომატიზაციის გარეშე ეს ასე გამოიყურება: სტატია გახსნა, სათაური გადაიწერა, კარუსელში დაბრუნება, სათაური ჩასვა, კვლავ სტატია გახსნა, აღწერილობა გადაიწერა, კვლავ დაბრუნება, ჩასვა, სახურავის სურათის URL გადაიწერა, დაბრუნება, ჩასვა.
ფუნქცია Autofill from Article ამ პროცესს ერთი მოქმედებით ცვლის. რედაქტორი ჩამოსაშლელი სიიდან სასურველ სტატიას ირჩევს — პანელი Firestore-ს მიმართავს, სტატიის დოკუმენტს იღებს და ახალი სლაიდის ველებში სათაურს, აღწერილობასა და სახურავს ავტომატურად ათავსებს. შედეგი მოწმდება და ერთი დაჭერით ინახება.
ეს პრინციპის მაგალითია, რომელსაც კლიენტებისთვის ინსტრუმენტების შემუშავებისას ვიცავთ: ავტომატიზება სჭირდება არა მხოლოდ ტექნიკურ, არამედ სარედაქციო პროცესებსაც.
Frontend Engine: SPA ფრეიმვორკების გარეშე
საიტი Single Page Application-ივით იქცევა — გვერდებს შორის გადასვლები მყისიერია, ინტერფეისის მდგომარეობა ინახება, ანიმაციები არ წყდება. ამავდროულად, build-ში არ არის React, Vue და არც Angular. კლიენტის მთელი ძრავი სუფთა Vanilla JS-ზეა დაწერილი.
ეს გაცნობიერებული არქიტექტურული გადაწყვეტილებაა და არა შემუშავებაზე დაზოგვა. ნებისმიერი JS-ფრეიმვორკი — ეს ბანდლის დამატებითი კილობაიტებია, runtime-ოვერჰედი ჰიდრატაციისას, ბრაუზერული API-ების თავზე აბსტრაქციები და ეკოსისტემაზე დამოკიდებულება, რომელიც პროექტებზე სწრაფად განახლდება. საიტისთვის, სადაც Time To Interactive-ის ყოველი მილიწამი მნიშვნელოვანია, ნათიური ბრაუზერული JavaScript — არ არის კომპრომისი, სწორი ინსტრუმენტია. ბრაუზერს უკვე ყველაფერი შეუძლია: History API, Intersection Observer, fetch, CustomEvent. საჭიროა მხოლოდ ამ მექანიზმების პირდაპირ გამოყენება.
Client-Side Routing History API-ის მეშვეობით
გვერდებს შორის გადასვლები ბრაუზერის გადატვირთვის გარეშეა განხორციელებული. კლიენტური როუტერი document დონეზე ღონისძიებების დელეგირების მეშვეობით შიდა ბმულებზე დაჭერას წყვეტს — ერთი დამმუშავებელი თითოეულ ბმულზე ცალკე listener-ის ნაცვლად. შემდეგ მიმდევრობა ასეთია:
history.pushState()-ის გამოძახება მყისიერად ამახლებს URL-ს მისამართის ზოლში გვერდის გადატვირთვის გარეშე.- სამიზნე HTML-ფაილი
fetch()-ის მეშვეობით იტვირთება — მოთხოვნა CDN-ს მიდის, რომელიც მზა სტატიკურ ფაილს გასცემს. - ჩატვირთული HTML-იდან
DOMParser-ის მეშვეობით
თეგის შინაარსი გამოიწყვეტება და მიმდინარე გვერდის DOM-ში ჩაიცვლება.<main> - ახლდება ანიმაციების დამკვირვებლები, ღონისძიებათა დამმუშავებლები და ახალი გვერდის ყველა ინტერაქტიული კომპონენტი.
popstateდამმუშავებელი ბრაუზერული ნავიგაციის ღონისძიებებს წყვეტს და "უკან" ও "წინ" ღილაკების დაჭერისას იმავე ლოგიკას ახდენს.
მნიშვნელოვანი დეტალი, რომლის გამოტოვება ადვილია: ბრაუზერში SPA-ქცევის მიუხედავად, თითოეული გვერდი დისკზე სრულყოფილ სტატიკურ HTML-დოკუმენტად რჩება. URL-ზე პირდაპირი გადასვლა, ბმული მესენჯერიდან, საძიებო ბოტის ინდექსაცია — ყველაფერი კორექტულად და სერვერული როუტინგის გარეშე მუშაობს, რადგან ფაილი ფიზიკურად საჭირო მისამართზე არსებობს. ეს კლასიკური SPA-ებისგან პრინციპული განსხვავებაა React Router-ზე ან Vue Router-ზე, რომლებიც "არარსებული" მარშრუტების დამუშავებისთვის სერვერულ კონფიგურაციას მოითხოვენ.
Intersection Observer: ლენივი ჩატვირთვა არა მხოლოდ სურათებისთვის
სტანდარტული პრაქტიკა — Intersection Observer API-ს გამოყენება სურათების ლენივი ჩატვირთვისთვის. ჩვენ მას გაცილებით ფართოდ ვიყენებთ: ამ API-ის მეშვეობით გვერდის ყველა მძიმე კომპონენტის ინიციალიზაცია კონტროლდება.
მძიმე ფონური ბლოკები მუშაობას არ იწყებენ, სანამ მომხმარებლის ხედვის არეალში არ მოხვდებიან. ეს ნიშნავს, რომ გვერდის ჩატვირთვისას ბრაუზერი რესურსებს არ ხარჯავს ხუთი ეკრანით ქვემოთ მყოფი ანიმაციების გამოთვლაზე. ეფექტი პირდაპირია: Total Blocking Time მცირდება, Largest Contentful Paint უმჯობესდება, მობილურ მოწყობილობებზე გვერდი გაცილებით სწრაფად ხდება რეაგირებადი.
სისტემაში სამი ტიპის დამკვირვებელია განხორციელებული პრინციპულად განსხვავებული ქცევის ლოგიკით:
- animateOnce — დამკვირვებელი ელემენტის viewport-ში პირველი მოხვედრისას ამოქმედდება, CSS-კლასს
is-visibleამატებს და მაშინვეunobserve()-ის მეშვეობით გამოირთვება. კლასი ელემენტზე სამუდამოდ რჩება. ეს არა მხოლოდ გამოჩენის ანიმაციების უმეტესობისთვის სწორი UX-მოდელია, არამედ გაცნობიერებული ოპტიმიზაციაა: გამორთული დამკვირვებელი შემდგომი გადახვევისას რესურსებს არ მოიხმარს. - animateAlways — კლასი ელემენტის viewport-ში შესვლისას ემატება და გამოსვლისას მოიხსნება. დამკვირვებელი არ გამოირთვება. გამოიყენება ელემენტებისთვის, რომლებმაც ყოველ ჯერზე უნდა გაუშვან ანიმაცია, როცა მომხმარებელი მათამდე გადახვევს — მაგალითად, მრიცხველებისთვის ან საძიებო ბლოკებისთვის.
- floatingObserver — გაფართოებული ლოგიკა, რომელიც მხედველობაში იღებს არა მხოლოდ ხილვადობის ფაქტს, არამედ ელემენტის პოზიციასაც viewport-თან შედარებით. ელემენტებს, რომლებიც მიმდინარე პოზიციის ზემოთ გადაიხვიეს, კლასი
is-aboveენიჭება. ეს ცალკე CSS-წესების გამოყენების საშუალებას იძლევა "გავლილი" სექციებისთვის — მაგალითად, parallax-გამოსვლის ეფექტის განხორციელება ან სათაურის სტილის ცვლილება, ბლოკიდან გამომდინარე, რომელიც უკან დარჩა.
Custom Backgrounds: იზოლირებული ანიმაციები iframe-ში
საიტის თითოეულ გვერდს შეუძლია ჰქონდეს უნიკალური ანიმირებული ფონი — p5.js-სქეჩი გენერაციული გრაფიკით, Three.js-სცენა 3D-ობიექტებით, GLSL-შეიდერი პროცედურული ტექსტურებით ან ნებისმიერი სხვა ვიზუალური ეფექტი. ფონის კოდი Firestore-ში თვითნებური HTML/CSS/JS-სტრიქონად ინახება, ადმინ-პანელის ველში ჩაისმება და გვერდის გენერაციისას
<iframe> თეგში თავსდება.iframe-ის გამოყენება — გამარტივება კი არ არის, არამედ განზრახი არქიტექტურული გადაწყვეტილება, რომელიც ერთდროულად ორ დაუკავშირებელ პრობლემას წყვეტს.
პირველი — უსაფრთხოება. ფონის კოდი ბრაუზერის სრულად იზოლირებულ კონტექსტში სრულდება: მას ძირითადი გვერდის DOM-ზე წვდომა არ აქვს, JavaScript-ცვლადების კითხვა არ შეუძლია, მომხმარებლის მონაცემებს ვერ ხედავს და ინტერფეისის ღონისძიებებს ვერ გადაწყვეტს. ეს მნიშვნელოვანია, რადგან ფონის ველი ადმინ-პანელის მეშვეობით არის ხელმისაწვდომი, და იზოლაცია ძირითადი ინტერფეისის შემთხვევით ან განზრახ გამორთვას გამორიცხავს.
მეორე — შესრულება. მძიმე გამოთვლები — WebGL-რენდერინგი, ნაწილაკების ფიზიკური სიმულაციები, შეიდერების პიქსელ-პიქსელ ოპერაციები — ცალკე რენდერინგის კონტექსტში სრულდება და პროცესორის რესურსებზე ძირითად ნაკადთან კონკურენციაში არ იმყოფება. მომხმარებელი მდიდარ ვიზუალურ ფონს ხედავს, სანამ ინტერფეისი რეაგირებადი რჩება და ინტერაქციისას კადრებს არ კარგავს.
Glow Carousel: მათემატიკა UI დონეზე
კარუსელი მთავარ გვერდზე — ეს სტანდარტული CSS-სლაიდერი overflow: hidden-ით და კლასების გადართვით არ არის. ეს კომპონენტია ფიზიკურად დასაბუთებული სინათლის ბზინვის ეფექტით, რომელიც რეალურ დროში კურსორის პოზიციაზე რეაგირებს.
ეფექტის ბირთვი — ორი არგუმენტის არქტანგენსის ფუნქციაა: atan2(dy, dx). კარტოჩზე კურსორის გადაადგილებისას კომპონენტი კარტოჩის ცენტრიდან კურსორის მიმდინარე პოზიციამდე ვექტორს ითვლის. ფუნქცია atan2 ამ ვექტორს -π-დან π-მდე დიაპაზონში კუთხედ გარდაქმნის. კუთხე გრადუსებად გადაითარგმნება და CSS-გრადიენტის მიმართულებად გამოიყენება, რომელიც ბზინვას ქმნის. კარტოჩის ცენტრიდან კურსორამდე მანძილი ეფექტის ინტენსივობას clamp() ფუნქციის მეშვეობით განსაზღვრავს.
შედეგი: ბზინვა ფიზიკურად კორექტულად "მიჰყვება" სინათლის წყაროს — მომხმარებლის კურსორს. ეს არ არის ტაიმერის ანიმაცია და არც წინასწარ ჩაწერილი keyframe, არამედ გამოთვლა რეალურ დროში ყოველ mousemove ღონისძიებაზე.
ბზინვის ეფექტის გარდა, კარუსელში ინჟინერული გადაწყვეტილებების რიგია განხორციელებული:
- ფონური სურათების Lazy Loading
data-bg-srcატრიბუტის მეშვეობით. კარტოჩის სურათი არ ჩაიტვირთება, სანამ კარტოჩი აქტიური არ გახდება. CSS-თვისებაbackground-imageპროგრამულად მხოლოდ სლაიდის ჩვენების მომენტში ხდება, რის შემდეგაცdata-bg-srcატრიბუტი იშლება — განმეორებითი ჩატვირთვა არ ხდება. - ანიმაციის შეწყვეტისგან დაცვა ბულეანური ფლაგ
isAnimating-ის მეშვეობით. თუ მომხმარებელი სლაიდებს შორის გადასვლის დასრულებამდე ისარს სწრაფად დააჭერს, ახალი გადასვლა მიმდინარეს დასრულებამდე არ იწყება. ეს ვიზუალური არტეფაქტებისა და კომპონენტის არასწორი მდგომარეობის თავიდან აცილებას უზრუნველყოფს. - ნავიგაციის დინამიური გენერაცია. ინდიკატორი-წერტილები და ისრები Firestore-იდან მიღებული სლაიდების რეალური რაოდენობის საფუძველზე პროგრამულად იქმნება. შაბლონი ჩაჰარდქოდებულ ნავიგაციის ელემენტებს არ შეიცავს.
- თემების მხარდაჭერა
isLightThemeფლაგის მეშვეობით. კომპონენტი ლოგიკის გაორმაგების გარეშე ბზინვის ფერის სქემას გვერდის ღია ან მუქ თემასთან ადაპტებს.
შედეგები: რა მივიღეთ საბოლოოდ
ამ კეისში აღწერილი არქიტექტურა — ეს არ არის ექსპერიმენტული შემუშავება და არც აკადემიური სავარჯიშო. ეს პროდაქშენ-სისტემაა, რომელიც ყოველდღიურად სააგენტოს საიტს ემსახურება და კლიენტური პროექტებისთვის გამეორებადია იქ, სადაც ამოცანა მაქსიმალური ტექნიკური ხარისხს მოითხოვს.
TTFB ნულთან ახლოს: სერვერი არ ფიქრობს — ის გასცემს
Time To First Byte — მოთხოვნის გაგზავნიდან პასუხის პირველი ბაიტის მიღებამდე დრო — პრაქტიკულად 117 მს-ის ტოლია. სერვერი მოთხოვნის მიხედვით ვერცერთ გამოთვლას არ ასრულებს: მონაცემთა ბაზასთან მოთხოვნები არ არის, PHP ან Node.js-ი, სერვერული რენდერინგი. CDN მოთხოვნას იღებს და ახლოს მყოფი დამსწრე პუნქტის კეშიდან მყისიერად გასცემს მზა HTML-ფაილს.
შედარებისთვის: WordPress აგრესიული კეშირების ფასიანი პლაგინით ხელსაყრელ პირობებში იძლევა TTFB 80–200 მს.
სერვერული რენდერინგი არ არის: საბრძოლო ბექენდი — ნული
პროდაქშენ-სერვერზე არ არის Node.js, PHP და არც მომუშავე მონაცემთა ბაზა. ინფრასტრუქტურა მინიმუმამდეა დაყვანილი: Firebase Firestore მონაცემებს ინახავს და მხოლოდ შეგროვებისას არის ხელმისაწვდომი, CDN სტატიკურ ფაილებს გასცემს. ეს ნიშნავს მთელი კლასის პრობლემების არარსებობას — სერვერული კოდის დაუცველობები, მეხსიერების გაჟონვები, მონაცემთა ბაზის დაცემა დატვირთვის ქვეშ, სერვერული გარემოს განახლების საჭიროება.
SEO "ყუთიდან": მარკირება, როგორც შეგროვების შედეგი, და არა ხელის შრომა
გენერაციისას თითოეული გვერდი ავტომატურად იღებს ტექნიკური SEO-მარკირების სრულ კომპლექტს: კორექტულ hreflang თეგებს ყველა ენობრივი ვერსიისთვის რეგიონული სუფიქსებით, სწორად დანიშნულ x-default-ს, კანონიკურ URL-ს, Open Graph-თეგების სრულ კომპლექტს სოციალური ქსელებისთვის, sitemap.xml-ში აქტუალურ ჩანაწერს მონაცემთა ბაზიდან ბოლო ცვლილების რეალური თარიღით.
სისტემის პირველადი კონფიგურაციის შემდეგ ამ თვისებებიდან ვერცერთი ხელით კონტროლს არ საჭიროებს. რედაქტორი ახალ სტატიას ამატებს — მომდევნო შეგროვებისას ის ავტომატურად გამოჩნდება sitemap-ში კორექტული მეტათეგებით და ყველა თარგმანთან hreflang-კავშირებით.
მასშტაბირება ხარჯების გარეშე: ტრაფიკი იზრდება, ანგარიში — არა
სტატიკური ფაილები CDN-ის მიერ გაიცემა. ჰოსტინგის ღირებულება ვიზიტორების რაოდენობაზე არ არის დამოკიდებული: ათასი მოთხოვნა დღეში და მილიონი მოთხოვნა დღეში ერთნაირად ღირს — ნულთან ახლოს. ეს პრინციპული განსხვავებაა სერვერული რენდერინგის ნებისმიერი არქიტექტურისგან, სადაც ტრაფიკის ზრდა პირდაპირ ოპერაციული ხარჯების ზრდაში გადადის.
ჰორიზონტალური მასშტაბირება ნაგულისხმევად უფასოა: CDN-პროვაიდერი დატვირთვას მთელ მსოფლიოში დამსწრე პუნქტებს შორის თვითონ ანაწილებს.
AI-ხილვადობა: მომდევნო თაობის ძიებისთვის მზადყოფნა
ფაილი llms-full.txt ყოველ deploy-ზე ახლდება და ენობრივ მოდელებს — ChatGPT, Claude, Perplexity და სხვებს — საიტის სრულ და სტრუქტურირებულ წარმოდგენას იძლევა: რით არის დაკავებული სააგენტო, რა სერვისებს გვთავაზობს, რა კონტენტია გამოქვეყნებული და რა ენებზე. ეს ინვესტიციაა მომავლის საძიებო ხილვადობაში, სადაც ტრაფიკის მნიშვნელოვანი ნაწილი AI-აგენტებით გენერირდება და არა კლასიკური საძიებო სისტემებით.
ტექნიკური კომპეტენციის დემონსტრირების საუკეთესო გზა — მისი მუშაობაში ჩვენებაა. ამ საიტის თითოეული გადაწყვეტილება კონკრეტული ამოცანითაა მოტივირებული, რომელიც შემუშავების დაწყებამდე ჩამოვაყალიბეთ.
თუ თქვენი პროექტი ინჟინერული სიზუსტის იმავე ხარისხს მოითხოვს — მზად ვართ მისი არქიტექტურა განვიხილოთ.