Όλες οι ενημερώσεις και τα νέα features του ChalkidikiHub
23 Μαΐου 2026
140 νέες παραλίες από OpenStreetMap με unique AI περιγραφές × 7 γλώσσες (980 νέες indexable σελίδες), public host pages για owners με ≥2 καταλύματα (νέο /host/[slug] route), νέα admin tools (hosts dashboard + mass-email segment), build perf fix για να μην ξαναχτυπήσουμε το 45-min Vercel ceiling
Νέο pipeline σε 6 scripts (`scripts/import-beaches-osm.js` κλπ) που τραβάει όλες τις natural=beach POIs στη Χαλκιδική από OpenStreetMap (free, no key), κάνει dedupe με proximity + same-name (250m strict, 800m όταν όνομα ταιριάζει), αυτο-classify σε kassandra/sithonia/athos/mainland με γεωγραφικούς κανόνες lat/lng, και upsert στο Supabase. Φιλτράρει non-beach POIs (bar/restaurant/hotel/camping tags). Συνολικά 165 παραλίες στο DB από 25 πριν.
Δύο OpenAI passes ανά παραλία: (1) gpt-4o-mini με per-beach style+tone seed από 8×3 = 24 παραλλαγές, hardcoded village proximity hints από lat/lng (~50 anchor villages), 80-120 word Ελληνικά κείμενο που αποφεύγει AI clichés ("κρυστάλλινα νερά", "παράδεισος") και ξεκινάει με μη-επαναλαμβανόμενες δομές. (2) Batch JSON translation σε 6 γλώσσες + per-locale meta_title (50-60 chars) + meta_description (140-155 chars). Συνολικό κόστος ~$0.80 για 140 παραλίες. Regex pass στο τέλος καθάρισε leftover coordinate strings που το AI έβαζε αυτούσιες (41 fixes).
Νέο scripts/enrich-beaches-osm-tags.js ξανατραβάει OSM beaches με πλήρη tags, ταιριάζει με τις DB rows με proximity (200m) και αντιστοιχίζει surface, sunbeds, naturism, wheelchair, lifeguard, access σε BeachFeature array. 81 παραλίες πήραν πραγματικά OSM features (sandy/pebble/nudist/free), 59 fallback "free". Όλες έχουν πλέον rating ≥ 3.5 ώστε ο crowd estimator (getPopularity στο crowd-estimation.ts) να βγάζει meaningful score αντί για 0.
Δύο scripts: `assign-beach-images-by-area.js` τραβάει 1 Unsplash photo ανά region (Kassandra/Sithonia/Athos/Mainland), τα ανεβάζει σε Supabase Storage και τα assign-άρει σε όλες τις παραλίες της περιοχής. `assign-per-beach-unsplash.js` σταδιακά αναβαθμίζει σε per-beach photos όπου το Unsplash έχει σχετικό αποτέλεσμα — 38 παραλίες έχουν ήδη unique cover (rate-limited στο demo tier 50/hr, συνεχίζεται με scheduled task).
Νέο SSR route που εμφανίζει την προσωπική σελίδα ενός ιδιοκτήτη με όλα του τα δημοσιευμένα καταλύματα σε grid, plus avatar/logo, 7-language bio, public contact (email/phone), social links (Facebook/Instagram/website), aggregate stats. Gating με ≥2 published listings + explicit toggle. Person JSON-LD schema + BreadcrumbList, canonical + 7 hreflang alternates, στο sitemap automatically. Migration 042 πρόσθεσε public_slug, public_page_enabled, bio_{el..sr}, social_*, public_{display_name,avatar,email,phone} στο profiles, με public-read RLS policy μόνο για enabled+slug rows.
Το dashboard profile section επεκτάθηκε με sections για host-page management: enable toggle (disabled μέχρι ≥2 published listings), manual slug με live preview + sanitization, public display name, avatar URL, public email/phone, Facebook/Instagram/website inputs, και bio editor σε 7 γλώσσες με collapsible textareas. Αυτόματο revalidate trigger στο /api/revalidate?type=host μετά το Save ώστε το production cache να ενημερωθεί άμεσα.
Νέο HostPagePromoBanner client component που εμφανίζεται σε owners με ≥2 published listings που δεν έχουν ακόμα ενεργοποιήσει host page. Gradient primary→indigo design με decorative blurs, 3 value props (one link / SEO+schema / AI discoverability), CTA σε /dashboard/profile. Όταν είναι enabled, αντικαθίσταται από compact "live" confirmation card με View page + Edit. Dismissable με sessionStorage persistence.
Server component που εμφανίζεται κάτω από κάθε listing detail page και προτείνει "Δες τα {N} άλλα καταλύματα του {host}" με link στο /host/[slug]. Φαίνεται μόνο όταν ο owner έχει public_page_enabled + ≥2 published + το current listing δεν είναι το μοναδικό άλλο. 7-locale copy.
Νέα σελίδα admin/hosts με 4 stat tiles (Enabled / Eligible-not-enabled για outreach / Total eligible / All owners) και sortable table που δείχνει για κάθε owner: avatar+name+email, slug+clickable production URL, listings count, bio fill status (✓/empty), status badge (Live/Eligible/—), και inline Enable/Disable button που κάνει αυτόματο revalidate. Filter chips (Enabled/Eligible/All) + search across name/email/slug.
Στο /admin/email προστέθηκε νέα κατηγορία παραληπτών για στοχευμένη outreach προς owners που είναι eligible αλλά δεν έχουν ενεργοποιήσει τη σελίδα τους ακόμα. Bonus: το listingCount σε όλο το email panel μετράει πλέον μόνο published listings (πριν περιελάμβανε drafts/closed), ώστε οι αριθμοί να συμπίπτουν με αυτούς του /admin/hosts.
Μετά το 45-min Vercel build ceiling που χτύπησε με την εισαγωγή των +140 παραλιών (+980 SSG pages × 7 locales), το generateStaticParams για beaches/listings/restaurants/activities/blog άλλαξε σε `return []`. Pages renderάρονται στο first request και cache-άρονται για 1h μέσω του υπάρχοντος revalidate. Sitemap συνεχίζει να τις listάρει, οπότε το Google discovery δεν επηρεάζεται. Build time έπεσε από >45min σε ~3min.
Μετά το perf change, το /listings/[slug] (και άλλα) βγάζανε 500 γιατί στο Next.js 16 + Turbopack το generateStaticParams() που επιστρέφει [] δεν κάνει αυτόματο fallback σε on-demand σωστά. Προστέθηκε `export const dynamic = "force-dynamic"` στις detail routes για να γίνει instant fix. Επόμενο cycle: investigation για proper ISR config χωρίς force-dynamic, μόλις ξεκαθαρίσει το Next 16 behavior.
Ο αρχικός import classifier marked beaches με lon ≥ 23.92 ως Athos, αλλά το νότιο άκρο της Σιθωνίας εκτείνεται μέχρι lon ~24.0 (Sykia, Kalamitsi area). Conservative reclassification fix στο `scripts/fix-beach-areas.js` διόρθωσε 2 ξεκάθαρα λάθη (Σάρτη + Νέος Μαρμαράς από athos σε sithonia), αφήνοντας borderline cases (Άγιος Γεώργιος Σιθωνίας @ 40.32) ως είχαν.
Νέο /api/admin/storage-relabel endpoint που backfill-άρει long Cache-Control headers σε υπάρχοντα Supabase Storage uploads (πριν είχαν default 1h). Νέο storage-recompress για legacy oversized images. Vercel image optimizer απενεργοποιήθηκε προσωρινά για να ξεμπλοκάρει production downloads. Auto-blog cron μεταφέρθηκε σε weekly. PMS crons disabled (unused).
Rich per-page meta descriptions αντί generic site-wide fallback (από v3.34 baseline). Duplicate "ChalkidikiHub | ChalkidikiHub" στους titles αφαιρέθηκε. Auto-noindex σε /guide και /places translations που έχουν source description < threshold — Google δεν τιμωρεί πλέον για thin foreign-language pages όταν δεν υπάρχει substantive content. AI auto-fill admin endpoint για bulk content generation σε αυτά τα slots.
Το activity_logs τώρα αποθηκεύει την πλήρη λίστα emails που στάλθηκαν σε κάθε mass send. Νέο expandable panel στο send history δείχνει τη λίστα παραληπτών με Copy και "Επαναχρήση παραληπτών" buttons — άμεσο follow-up στους ίδιους χρήστες ως external recipients χωρίς να ξαναστήσεις το φίλτρο.
Νέο PINNED_LISTING_SLUG_PREFIXES array στο data.ts + pinFeaturedListings() helper που εξασφαλίζει συγκεκριμένα listings (αρχικά Amira House) εμφανίζονται πάντα πρώτα στο /listings index και στο homepage, ανεξάρτητα από τη χρονολογική σειρά δημιουργίας. Wire-up σε getListings().
7 Μαΐου 2026
AdSense compliance overhaul, 532 νέες σελίδες με AI-generated owner stories (76 listings × 7 γλώσσες), 3 data-driven features (sea temperature, price benchmarks, driving distances), νέα /about, honest cookie consent + GDPR-clean privacy
Συνολικό overhaul για το AdSense rejection. /book/[slug] "under construction" placeholders → 308 permanentRedirect στο /listings/[slug] (462 thin URLs εξαφανίστηκαν). AdSense adsbygoogle.js βγήκε από το interaction-gate και φορτώνει με afterInteractive ώστε ο reviewer crawler να το ανιχνεύει. /changelog noindex (internal/dev content). /in/[location]/[category] επιστρέφει 404 όταν τα results είναι 0, αντί για κενό template. /listings/[slug] auto-noindex όταν source description < 200 chars (νέο thinThreshold option στο getContentMeta).
CookieConsent ξαναγράφτηκε σε 7 γλώσσες με ειλικρινές copy (αναφέρει ρητά Google AdSense + Google Analytics + opt-in mechanism), granular επιλογή Accept all / Essential only, link σε privacy. DeferredScripts τώρα setάρει window.adsbygoogle.requestNonPersonalizedAds=1 πριν φορτώσει το script όταν consent είναι unknown ή rejected — non-personalized ads χωρίς consent. GA φορτώνει μόνο μετά από explicit accept (παραμένει gated σε interaction/idle για LCP/TBT).
Πλήρης About page (~430 λέξεις/locale) με sections "Mission / What you will find / How we are different / Get in touch", AboutPage JSON-LD με Organization mainEntity (founder, foundingDate, contact, areaServed, sameAs social), σωστά canonical + 7 hreflang alternates + x-default. Footer link στο "Legal" column με tNav("about"). Sitemap entry για /about × 7 locales. Trust signal που έλειπε για AdSense.
Νέο /api/sea-temperature route που καλεί Open-Meteo Marine API (free, no key, edge-cached 1h). Νέο SeaTemperatureCard component εμφανίζει current temp + 7-day forecast + monthly historical heatmap (Aegean baseline) σε 60+ beach pages. Πραγματικά μοναδικά live data για κάθε παραλία.
Νέο place-stats.ts helper με 2 functions: getVillagePriceStats (avg/min/max με comparison vs Halkidiki overall, ≥3 listings required) και getVillageCuisineStats (Greek/traditional vs international ratio βασισμένο σε cuisine tags, area-fallback όταν <5 categorised). Δύο νέα cards στο VillagePage μετά το quick-stats grid, locale-aware copy σε 7 γλώσσες. Παράδειγμα Toroni: "€116/βραδιά, 14% πιο φθηνά από Χαλκιδική avg, δείγμα 6", "33% παραδοσιακά εστιατόρια / 67% διεθνή".
Νέο driving-distances.ts: Haversine + 1.4× road factor + adaptive speed (55/70/85 km/h ανά trip length) χωρίς external routing API. Coordinates + localised names για όλες τις 8 origin cities. Νέο DistanceTable component εμφανίζει sortable table με 11 popular Halkidiki villages + km + drive time + links στο /places/[slug]. 7-locale copy + disclaimer.
Νέο /api/admin/generate-owner-stories endpoint που με 1 cURL γεμίζει το owner_story_<locale> field για όλα τα 76 published listings σε 7 γλώσσες. Δύο OpenAI calls per listing: gpt-4o-mini για 150-200 word Greek narrative grounded σε real facts (location, capacity, amenities), batch JSON translation σε en/de/bg/ru/ro/sr (sr σε Latin script). Bulk-run κάλυψε 100% των 76 listings (35 + 33 + 8 pre-existing) με 0 failures, ~$0.40 OpenAI cost. Total: 532 σελίδες με original AI-written content που δεν υπάρχει αλλού.
Section 5 ξαναγράφτηκε σε el/en/de/bg/ru/ro με σαφή τρεις κατηγορίες cookies (essential / advertising-AdSense / analytics-GA) και reference στο cookie banner ως opt-in mechanism. Το προηγούμενο "no tracking cookies" copy ήταν σε αντίφαση με το νέο banner — αυτό από μόνο του θα μπορούσε να δικαιολογήσει AdSense rejection.
Δύο pre-existing bugs που εμφανίστηκαν μόνο σε next build (Turbopack dev mode τα έπιανε): import path του villages_body.json είχε 7 ../ levels (έβγαινε εκτός project root) → 6, και το cast listing as Record<string, string|null> χρειάστηκε intermediate as unknown γιατί το listing_images array δεν είναι compatible με string.
21 Απριλίου 2026
Area guide σε όλα τα 66 καταλύματα × 7 γλώσσες (462 νέες indexable σελίδες), /book κλειδωμένο με contact-only, PMS kill-switch
Το area guide που πριν δούλευε μόνο στο Thespis Villa 3 είναι τώρα live σε όλα τα 66 καταλύματα × 7 γλώσσες. Κάθε οδηγός έχει τις 6 κοντινότερες παραλίες, 8 εστιατόρια και 6 δραστηριότητες ταξινομημένα με Haversine distance, 3ήμερο προτεινόμενο itinerary, FAQ section με airport transfer info, και 4 internal links προς σχετικά καταλύματα (village-first, area-fallback). Κάθε guide: ~350KB HTML, ~10 JSON-LD schemas, πλήρως SSR, ISR revalidate 24h
Το πρώτο audit έδειξε 13 Kassandra listings με μόνο 3 εστιατόρια και 2 mainland listings με 2 παραλίες (λόγω sparse δεδομένων στις αντίστοιχες περιοχές). Αντί να περιοριστώ σε .eq("area", area), τώρα φέρνω POIs από όλη τη Χαλκιδική και ταξινομώ με πραγματική απόσταση. Η Χαλκιδική είναι αρκετά μικρή ώστε ένα beach 10χλμ μακριά να είναι πιο χρήσιμο από padding με 2-item section. Μετά το fix: όλα τα 66 guides έχουν 6 παραλίες + 8 εστιατόρια + 6 δραστηριότητες
Κάθε area guide έχει τώρα Article schema με datePublished/dateModified, author (ChalkidikiHub), publisher με logo, εικόνα κάλυψη του καταλύματος. Open Graph image 1200×630 με alt text + Twitter summary_large_image card. Η Google τα πιάνει ως content articles αντί για product pages — unlocks "News & Discover" placement
Κάθε guide δείχνει 4 σχετικά καταλύματα: priority στο ίδιο χωριό (stronger topical signal), fallback σε ίδια περιοχή αν το χωριό έχει <4 listings. Εικόνα, τιμή, link — το καθένα τραβάει crawl equity στο source listing. 462 guides × 4 links = 1.848 νέα εσωτερικά paths, αυξάνει crawl depth + PageRank flow σε όλο το directory
Το online booking δεν είναι έτοιμο ακόμα. Αντί για half-baked form, η /book/[slug] σε 7 γλώσσες δείχνει "Online κρατήσεις υπό κατασκευή — επικοινωνήστε απευθείας με τον ιδιοκτήτη" με tel:/mailto:/wa.me/website buttons. robots: noindex, follow — δεν χάνουμε link equity, αλλά και δεν γεμίζουμε τη Google με thin "coming soon" pages. Link πίσω στο listing
Νέο pms_enabled flag στο pms_owner_settings (migration 039). Αν ένας owner έχει pms_enabled=false, όλα τα public API routes (/api/pms/public/{book,quote,checkout}) επιστρέφουν 503 pms_disabled. Admin dashboard τώρα έχει toggle για instant activation/deactivation χωρίς να πειράξουμε τα existing listings — χρήσιμο για phased rollout ή emergency stop
Το "Οδηγός περιοχής: {village}" CTA εμφανίζεται τώρα σε κάθε listing page (πριν εμφανιζόταν μόνο αν είχε lat/lon). BookOpen icon + area name, link σε /stay/{slug}/guide. 7-locale translations. Δίνει visibility στα νέα 462 guide URLs μέσα από τη φυσική user journey
Το /sitemap.xml τώρα περιλαμβάνει uncontionally /stay/{slug}/guide για κάθε listing × 7 γλώσσες, priority 0.8, changefreq weekly, lastmod από updated_at. Η Google παίρνει ρητό signal ότι αυτές είναι canonical σελίδες που θέλουμε indexed
21 Απριλίου 2026
SEO — SSR village pages, smart data-driven meta, FAQ schema: fix για 1.510 "Discovered, not indexed" URLs στο GSC
Μετά το v3.31.0, η αλλαγή από dynamic="force-dynamic" σε revalidate=3600 έσπασε όλα τα village pages γιατί το generateStaticParams() επέστρεφε άδεια λίστα → Next.js προσπάθησε static render αλλά το setRequestLocale() καλεί headers() → "Page changed from static to dynamic at runtime" error. Hotfix επαναφέρει force-dynamic προσωρινά (eb9071e), permanent solution στο ίδιο version: το generateStaticParams τώρα κατεβάζει όλα τα village slugs από Supabase και τα pre-renderάρει
VillagePage + VillageContentPage μετατράπηκαν από Client Components με useEffect fetch σε Server Components με pre-fetched props. Η Google βλέπει πλήρες HTML χωρίς JS — ονόματα παραλιών, εστιατορίων, δραστηριοτήτων, FAQs, όλα στο initial response. generateStaticParams σε /places/[slug] + /beaches + /restaurants + /activities pre-renderάρει 67 χωριά × 7 γλώσσες × 4 σελίδες ≈ 1.876 static pages στο build time. Instant TTFB από Vercel edge cache αντί για Supabase query ανά crawl
revalidate=3600 (1 ώρα) αντικαθιστά το force-dynamic hotfix. Κάθε village σελίδα ξανα-generάρεται μία φορά την ώρα στο background — ο crawler βλέπει cached HTML, οι real users βλέπουν fresh data. Η Supabase τώρα τρέχει ~67 queries/ώρα συνολικά αντί για ~67 queries ανά crawler visit. Crawl budget της Google δεν καίγεται σε slow dynamic responses
buildFaqs() helper στο /places/[slug]/page.tsx παράγει 2-4 questions ανά χωριό βασισμένες σε πραγματικά counts: "Πού βρίσκεται η {village};", "Υπάρχουν παραλίες κοντά;" (αν >0), "Πού να φάω;" (αν >0), "Τι να κάνω;" (αν >0). EL + EN variants — απαντήσεις template-ized με τα actual counts ώστε η Google να τα θεωρεί αξιόπιστα. BreadcrumbList + Place schema ήδη υπήρχαν, τώρα τρία schemas συν-εμφανίζονται στο head
GSC audit έδειξε 66/67 villages με meta_description_el που ξεκινάει με "Ανακαλύψτε την X..." — near-duplicate template που η Google downrankάρει. Το generateMetadata στο /places/[slug]/page.tsx τώρα τρέχει 3 count-only queries (beaches/restaurants/activities για το area) παράλληλα με top 2 beach names, και χτίζει unique per-village meta: "Σάρτη (Σιθωνία, Χαλκιδική): 7 παραλίες (Κληματαριά, Καρύδι), 58 εστιατόρια και 8 δραστηριότητες. Οδηγός, κριτικές, χάρτες." Localized σε 7 γλώσσες με σωστά plurals + conjunctions (και/and/und/и/și/i)
Το meta-helper.ts τώρα φέρνει count + top 2 ranked items ανά (village, content type) και γράφει unique title + description + H1. Πριν: "Best beaches near Sarti, Χαλκιδική." Μετά: "7 παραλίες κοντά στο Σάρτη (Σιθωνία, Χαλκιδική) — Παραλία Κληματαριά, Καρύδι. Φωτογραφίες, χάρτες, κριτικές." Η ίδια λογική τρέχει και στο H1, οπότε και το heading της σελίδας είναι unique — όχι μόνο το head tag. Συνολικά ~1.407 νέα unique routes (67 × 7 × 3)
Το sr locale έλειπε από τα LABELS του meta-helper.ts και από το metadata query στο /places/[slug]/page.tsx. Προστέθηκε στις 3 content-type maps (beaches/restaurants/activities), στα meta_title_sr + meta_description_sr columns του village query, και στο META_LABELS table για το smart description generator. Όλα τα 7 locales τώρα παράγουν properly localized output (Χαλκιδική/Halkidiki/Chalkidiki/Халкидики/...)
Κάθε metadata.alternates.languages map τώρα περιλαμβάνει x-default που δείχνει στην Ελληνική έκδοση (default locale). Η Google / Bing ξέρουν ποια γλώσσα να σερβίρουν σε visitors εκτός των 7 υποστηριζόμενων locales αντί για guessing με Accept-Language header. Ενσωματωμένο σε /places/[slug] και στις 3 subpages
20 Απριλίου 2026
5 νέοι travel guides + SEO comprehensive upgrade: CSP, hreflang x-default, Activity Schema.org, noindex hardening
Νέα κείμενα στο /guide/first-time-halkidiki, /guide/kassandra-sithonia-athos, /guide/hiking-halkidiki, /guide/wine-tours-halkidiki, /guide/petralona-cave. Ελληνικό content ~2000 λέξεις ανά guide με τοπικά insider tips ώστε να μην φαίνεται AI-generated, + μεταφράσεις σε 6 γλώσσες (en/de/bg/ru/ro/sr). 96-139 internal links ανά guide με hub&spoke strategy προς /places/<village>, /best/<collection>, /beaches/feature/<feature>, /itinerary/<days>, /from/<city>, /mount-athos. Καθένας έχει Article JSON-LD, OG images, hreflang alternates σε 7 γλώσσες
Προσθήκη CSP header σε όλες τις responses ως defense in depth vs XSS: default-src self, script-src self unsafe-inline unsafe-eval (για Next inline scripts), style-src self unsafe-inline (για Tailwind JIT), img-src self data: https:, font-src self data:, frame-src self https://js.stripe.com. Αν κάτι προσπαθήσει να κάνει inject remote script από unknown origin, ο browser το μπλοκάρει πριν εκτελεστεί
Το generateActivityLD() στο seo.ts μετατρέπει πλέον την κατηγορία (water-sports, spa, nightlife, religious, adventure) σε αντίστοιχο Schema.org subtype: SportsActivityLocation για water-sports/adventure, HealthAndBeautyBusiness για spa, NightClub για nightlife, PlaceOfWorship για religious. Προστέθηκαν επίσης πεδία touristType, image, priceRange, duration, geo.latitude/longitude και aggregateRating (conditional — μόνο αν υπάρχουν reviews). Google τώρα καταλαβαίνει τι είναι η κάθε δραστηριότητα αντί για γενικό TouristAttraction
Κάθε σελίδα (places, beaches, guides, activities, restaurants, blog, faq, itinerary, from, costs, ev-chargers, sales, stay, best, mount-athos και όλες οι υπόλοιπες) δηλώνει τώρα x-default alternate που δείχνει στην Ελληνική έκδοση του URL. Μαζί με τα 7 locale alternates, Google και Bing ξέρουν ποια γλώσσα να σερβίρουν σε επισκέπτες που δεν ταιριάζουν με κανένα από τα υποστηριζόμενα locales — αντί για guessing με βάση το Accept-Language header
Το /robots.txt πλέον απαγορεύει ρητά τα paths /admin, /dashboard, /api, /auth, /owner, /_next για όλους τους crawlers. Επιπλέον, ο proxy.ts στέλνει X-Robots-Tag: noindex, nofollow header σε κάθε response από private routes — έτσι ακόμα κι αν κάποιος bot αγνοήσει το robots.txt (το οποίο είναι advisory, όχι enforcing), το header βλέπεται στο response πριν γίνει index. Defense in depth σε δύο επίπεδα
Διαγραφή του legacy src/lib/json-ld.ts (51 lines που διπλάσιαζε helpers). Όλα τα JSON-LD builders πλέον ζουν σε ένα αρχείο: generateBreadcrumbLD, generateFAQLD, generateArticleLD, generateActivityLD, localeUrl, ogImageUrl, collectionMeta. +81 lines στο seo.ts για τα συνενωμένα helpers. Κάθε page/layout έχει ενημερωθεί ώστε να κάνει import από μόνο ένα place — μικρότερο bundle, λιγότερη duplication, ευκολότερη συντήρηση
Το /sitemap.xml τώρα περιλαμβάνει x-default alternate για κάθε URL alongside τα 7 locale alternates ώστε να είναι coherent με τα metadata alternates. /api/og route στέλνει Cache-Control: public, max-age=31536000, immutable — OG images cache-άρονται για 1 έτος από CDN + browsers χωρίς regeneration. ImageGallery thumbnail buttons έχουν aria-label για screen readers. Το not-found.tsx τώρα έχει localized metadata και translated strings και στις 7 γλώσσες αντί για hard-coded Ελληνικά
19 Απριλίου 2026
PMS — Stripe Connect: OAuth onboarding + deposit auto-charge με 0% commission
Νέο κουμπί "Connect with Stripe" στο /dashboard/pms/settings → Payments που κάνει redirect στο https://connect.stripe.com/oauth/authorize. Ο owner συνδέει τον Stripe λογαριασμό του (ή φτιάχνει καινούργιο με τα στοιχεία της επιχείρησης), και μετά το Stripe τον στέλνει πίσω στο /api/stripe/connect/callback όπου ανταλλάσσουμε το authorization code με stripe_user_id. Αποθηκεύεται σε pms_owner_settings.stripe_account_id + stripe_onboarded=true
Πριν το redirect, το /api/stripe/connect/start γεννάει 64-char hex random state μέσω crypto.getRandomValues() και το αποθηκεύει στο pms_owner_settings.stripe_connect_state του owner. Το callback ψάχνει τον owner μέσω του state value — αν δεν ταιριάξει, επιστρέφει state_mismatch. Έτσι κανείς δεν μπορεί να προσαρτήσει Stripe account άλλου σε owner χωρίς να ξέρει το token. Καθαρίζεται μετά την επιτυχία ή αποτυχία
Όταν guest κάνει direct booking σε owner με Stripe onboarded, το /api/pms/public/checkout δημιουργεί Stripe Checkout Session με payment_intent_data[transfer_data][destination]=<owner>.stripe_account_id και application_fee_amount=0. Αυτό σημαίνει ότι τα χρήματα πάνε κατευθείαν στον owner — η ChalkidikiHub δεν κρατάει τίποτα. Το 0% commission είναι η υπόσχεση της πλατφόρμας υλοποιημένη σε κώδικα
Το Checkout χρεώνει μόνο το deposit portion (total × deposit_percentage / 100) σε cents, όχι ολόκληρο το ποσό. Έτσι ο guest δεν επιβαρύνεται με 100% προκαταβολή και το balance (70-80% συνήθως) τακτοποιείται off-platform με bank transfer ή cash πριν το check-in, όπως προτιμάνε οι Έλληνες ιδιοκτήτες. Currency = listing currency (default EUR), product_data.name = "Villa + check_in → check_out"
Νέο endpoint που λαμβάνει checkout.session.completed event. Επαληθεύει το stripe-signature header με HMAC-SHA256 μέσω Web Crypto API (crypto.subtle.importKey + sign) και 5-min tolerance window ενάντια σε replay attacks. Βάζει το booking σε payment_status=deposit_paid + stripe_paid_amount (από amount_total/100) + stripe_payment_method + stripe_checkout_session_id. Unsigned ή malformed webhooks απορρίπτονται με 400
Αν ο owner έχει Stripe onboarded, το book API επιστρέφει stripe_enabled=true στο response. Το /book/[slug] τότε αντί να πάει στο confirmed, καλεί /api/pms/public/checkout και redirectάρει στο session.url. Ο guest πληρώνει στο Stripe-hosted checkout page, επιστρέφει στο /success → /confirmed. Αν αποτύχει (cancel button), πάει στο /cancelled με "Try paying again" button που ξανακαλεί το ίδιο endpoint
ALTER pms_owner_settings ADD stripe_connect_state TEXT (nullable, για OAuth flow). ALTER pms_bookings ADD stripe_checkout_session_id TEXT + stripe_paid_amount NUMERIC(10,2) + stripe_payment_method TEXT. Partial index idx_pms_bookings_stripe_session WHERE stripe_checkout_session_id IS NOT NULL για γρήγορο lookup από webhook. Καθαρά nullable ώστε να μην σπάει existing rows — όλοι οι owners ξεκινούν non-onboarded και το stripe flow είναι opt-in
19 Απριλίου 2026
PMS — Public direct booking page: 0% commission, απευθείας με τον ιδιοκτήτη
Guest-facing booking form σε rose→pink→fuchsia gradient χωρίς login. Hero με cover image του καταλύματος + εκπτωτικό badge "0% OTA". Split layout: αριστερά τα fields (dates, guests counter με +/-, name, email, phone, country, notes), δεξιά sticky quote card με nightly average, νύχτες, σύνολο, applied rules, deposit amount, cancellation policy & instant-book/needs-approval chip
Κάθε αλλαγή σε dates/listing καλεί /api/pms/public/quote που εφαρμόζει όλα τα active pms_pricing_rules του καταλύματος (seasonal, weekend, LOS, last-minute, custom) μέσω του υπάρχοντος computeQuote(). Εμφανίζει applied rules με signed delta (+ rose αν ακριβότερο, − emerald αν φθηνότερο). Υπολογισμός deposit με βάση το effective deposit_percentage από mergeSettings()
Το /api/pms/public/quote ελέγχει ταυτόχρονα: (1) listing_availability blocks στο range, (2) επικαλυπτόμενες pms_bookings εκτός cancelled, (3) min/max nights από effective settings, (4) advance_notice_hours vs τρέχουσα ώρα. Επιστρέφει availability.available + conflicts[] list ώστε το UI να δείξει τον λόγο (π.χ. "Minimum 3 nights") αντί για generic "unavailable"
Δημιουργεί pms_bookings row με source=direct και status=confirmed αν instant_book ON, αλλιώς inquiry. Service client παρακάμπτει RLS για το insert. Server-side re-validation όλων των checks (dates, min/max nights, availability, guest limits, email format) — ο client δεν ελέγχεται. Επιστρέφει 409 αν οι ημερομηνίες κλείστηκαν εν τω μεταξύ από άλλον channel
Redirect μετά το submit στο ?id=<booking-id>. Emerald-check icon αν confirmed, amber-clock αν inquiry. Δείχνει listing title, dates, guests, total σε fuchsia, booking ID σε mono. Contact tiles (phone/email) αν ο ιδιοκτήτης έχει ορίσει contact_phone/contact_email στο listing. "0% OTA" badge + link "Επιστροφή στο κατάλυμα"
Νέο rose button στο sticky price bar (δίπλα στην τιμή/νύχτα) που δείχνει "Κλείσε απευθείας — 0% προμήθεια" σε 7 γλώσσες (el/en/de/bg/ru/ro/sr). Sparkles icon + shadow-rose-500/30 για visual pop. Click → /book/<slug>. Inline στο ίδιο header με την τιμή ώστε να φαίνεται αμέσως η εναλλακτική σε OTA
Όταν δημιουργείται direct booking με status=inquiry ή confirmed, πέφτει στο ίδιο pms_bookings table που σκανάρει το /api/cron/pms-notifications (v3.28.0). Ο owner παίρνει email στο next :53 cron run χωρίς extra code — το source=direct filter δεν υπάρχει στον cron, οπότε καλύπτεται by default. Τοξεύεται επίσης στο ίδιο inbox/calendar όπου φαίνονται όλες οι κρατήσεις
19 Απριλίου 2026
PMS — Email alerts στον owner: inquiry, booking, overdue, check-in/out
Τρέχει στο :53 κάθε ώρας (ξεχωριστό window από dispatch :29 και auto-tasks :41 ώστε να μην συνωστίζονται τα sends). Σκανάρει 5 kinds: new inquiry (last 2h), new booking confirmed/pending (last 2h), overdue task (scheduled_at < now), check-in σήμερα, check-out σήμερα. Service client για cross-owner
Νέο email-alerts block μέσα στο Notifications section με 5 Toggle switches: notify_new_inquiry (default ON), notify_new_booking (ON), notify_overdue_tasks (ON), notify_check_in_today (OFF), notify_check_out_today (OFF). Κάθε toggle έχει hint που εξηγεί πότε στέλνεται
Όλα τα alerts γράφονται EL πάνω και EN από κάτω, χωρισμένα με horizontal divider ─────────────. Subject line: "Νέα κράτηση — Βίλα Καλλιθέα / New booking — Villa Kallithea". Έτσι δεν χρειάζεται να επιλέξεις locale — παίρνεις και τις δύο γλώσσες σε κάθε email
Νέος πίνακας pms_notifications με UNIQUE (owner_id, kind, ref_id, COALESCE(ref_date, epoch)). Για new_inquiry/new_booking το ref_date είναι NULL (one-shot). Για overdue_task το ref_date=today ώστε να re-notifyεί μία φορά την ημέρα όσο το task παραμένει overdue. Για check_in/out_today ref_date είναι η ίδια η ημερομηνία. Cron safe σε re-runs
Email alerts πηγαίνουν στο reply_to_email του owner settings — αν κενό, fallback στο auth.users.email του account (μέσω service.auth.admin.getUserById). Έτσι δεν χρειάζεται εξτρά setup για να λειτουργήσει — δουλεύει out-of-the-box με τα stored credentials του account
Export: sendOwnerAlert(supabase, {ownerId, kind, refId, refDate?, emailTo, subjectEl/En, bodyEl/En, creds?, footer?}) → "sent"|"skipped_duplicate"|"skipped_no_email"|"skipped_no_creds"|"failed". Reuses bodyToHtml + sendTemplateEmail + loadGmailCreds από dispatch.ts ώστε logic Gmail να είναι σε ένα μέρος. Records κάθε attempt (success or error) στο pms_notifications για audit
ALTER pms_owner_settings ADD 5 BOOLEAN columns (notify_*) με sensible defaults. Νέος πίνακας pms_notifications: id, owner_id FK CASCADE, kind TEXT (CHECK 5 values), ref_id TEXT, ref_date DATE, email_to, subject, sent_at, error, created_at. UNIQUE index με COALESCE sentinel 1970-01-01. 2 regular indexes (owner, sent_at DESC). RLS owner reads own + admin reads all — inserts γίνονται μόνο από cron με service client
20 Απριλίου 2026
PMS — Συνεργάτες (Vendors): λίστα επαφών για tasks
Amber-orange-rose gradient hero, κάρτες ανά συνεργάτη με avatar icon ανά role (καθαριστής, συντήρηση, property manager, κλινοσκεπάσματα, κηπουρός, φωτογράφος, άλλο). Filter bar: search (όνομα/email/τηλ), role dropdown, toggle "show inactive". Activate/deactivate με ένα click — inactive απορρίπτονται από το task picker αλλά δεν χάνονται
Modal form με 7 role icons σε grid (tapping χρωματίζει με το chipCls του role), name, phone, email, default hourly rate, default flat rate, notes. Autofocus στο name field. Live validation — save disabled αν δεν υπάρχει όνομα. Inline error από Supabase με mono font bubble
Optional reference με ON DELETE SET NULL ώστε αν διαγραφεί ο συνεργάτης, τα ιστορικά tasks παραμένουν (με το snapshot assignee_name/phone/email που είχαν τη στιγμή της ανάθεσης). Έτσι τα reports παραμένουν accurate χωρίς dangling refs ή auto-cascade
Νέο violet section "Πιάσε από συνεργάτες" πάνω από τα assignee fields: dropdown φορτωμένο με όλους τους active vendors. Όταν επιλέξεις συνεργάτη, γεμίζουν αυτόματα το name/phone/email/cost (default_flat_rate). Μπορείς πάντα να overrideάρεις χειροκίνητα — δεν "κολλάνε" τα πεδία
Κάθε κάρτα δείχνει αριθμό tasks που έχουν ανατεθεί σε αυτόν τον συνεργάτη (όλων των εποχών). Quick way να δεις ποιον χρησιμοποιείς πιο συχνά και ποιον ίσως αρχίζει να ξεχνάς. Ο αριθμός ενημερώνεται live κάθε φορά που φορτώνει η σελίδα
Κάθε vendor έχει προαιρετικά default_hourly_rate και default_flat_rate. Εμφανίζονται στην κάρτα με €amount/h και €flat font-mono. Όταν επιλεγεί στο task form, γεμίζει το flat rate αυτόματα στο cost field (αν δεν υπάρχει ήδη value). Hourly μένει για manual entry (e.g. αν η εργασία διήρκησε 2h)
Νέος πίνακας pms_vendors: id, owner_id FK, name, role (CHECK σε 7 values), phone, email, default_hourly_rate, default_flat_rate, notes, active, timestamps. 2 indexes (owner, active). RLS owner manages own + admin reads all. ALTER TABLE pms_tasks ADD vendor_id UUID REFERENCES pms_vendors ON DELETE SET NULL + index pms_tasks_vendor_idx
20 Απριλίου 2026
PMS — Per-listing overrides: κάθε κατάλυμα έχει τις δικές του πολιτικές
Dedicated page ανά κατάλυμα όπου ορίζεις overrides για instant_book, min/max nights, advance notice, preparation days, check-in/out times, cancellation policy, deposit %, balance days, κόστος καθάρισμα και lead days. Indigo-violet hero με το slug + live link, 4 sections χρωματιστά όπως τα global settings
Κάθε πεδίο έχει badge πάνω δεξιά: OVERRIDE (indigo, active) ή INHERIT (slate, πατώντας το επαναφέρει σε null). Όταν inherit, το input μετατρέπεται σε read-only box που δείχνει την effective τιμή από τα global defaults. Έτσι βλέπεις με μια ματιά ποια πεδία έχεις αλλάξει και ποια κληρονομεί
Νέα indigo section "Overrides ανά κατάλυμα" στο τέλος του /dashboard/pms/settings με λίστα όλων των καταλυμάτων. Κάθε row δείχνει title + slug + pinned badge με τον αριθμό των active overrides (π.χ. "3 overrides") ή "inherits defaults". Click → page του override
Exports mergeSettings(owner, listing) και resolveListingSettings(supabase, listingId, ownerId) που κάνουν tri-state resolution: listing override (αν not null) → owner default (αν not null) → hard default. Consumable από any route handler ή cron. Pure TS, καθαρά interfaces
Το /api/cron/pms-auto-tasks τώρα φορτώνει pms_listing_settings ανά owner και merge-άρει checkout_time + cleaning_lead_days + cleaning_default_cost ανά listing πριν δημιουργήσει το task. Έτσι αν ένα ακίνητο έχει 10:00 check-out και άλλο 13:00, τα tasks προγραμματίζονται σωστά
Κουμπί "Reset σε defaults" στο save bar που διαγράφει την entire row από pms_listing_settings (μέσω DELETE WHERE listing_id=...). Το κατάλυμα επιστρέφει σε full inheritance από owner settings σε όλα τα πεδία ταυτόχρονα — χωρίς να χρειάζεται να toggle-άρεις ένα-ένα
Νέος πίνακας pms_listing_settings με PK listing_id, όλα τα override columns NULLABLE (NULL = inherit). CHECK constraint για cancellation_policy μόνο όταν not null. RLS: owner manages own (auth.uid()=owner_id) + admin reads all. Updated-at trigger reused από pms_touch_updated_at()
20 Απριλίου 2026
PMS — Pricing Rules Engine: αυτόματο quote στο booking form
Pure TS function στο src/lib/pms/pricing.ts που παίρνει base_rate + dates + rules και υπολογίζει nightly breakdown. Per-night rules (seasonal/weekend/custom) εφαρμόζονται ανά ημέρα σε priority order, booking-scope rules (LOS/last-minute) μετά στο σύνολο. Σεβαστά operations: override/add/subtract/multiply, percentage ή absolute amount
POST {listing_id, check_in, check_out, booking_date?} → {base_rate, subtotal_*, nightly_average, applied[]}. RLS-scoped: verifyει ότι το listing ανήκει στον caller. Επιστρέφει array εφαρμοσμένων κανόνων με name, operation, scope (night/booking), nights_affected και signed delta σε €
Gradient fuchsia→pink box μέσα στο Money section που εμφανίζεται όταν listing + dates είναι set. Auto-fetch κάθε φορά που αλλάζει listing_id/check_in/check_out/status. Δείχνει 4 KPIs (Base/night, Avg/night, Nights, Subtotal) + λίστα εφαρμοσμένων κανόνων με icon (↑ rose αν ακριβότερο, ↓ emerald αν φθηνότερο, % για booking-scope)
Κουμπί μέσα στο quote box που γεμίζει nightly_rate (avg) + total_amount (subtotal + cleaning + taxes). Έτσι βλέπεις πρώτα την τιμή, μετά επιλέγεις αν θα την κρατήσεις ή θα κάνεις manual override (το pricing rules engine προτείνει, δεν επιβάλλει)
Όταν το booking είναι status=blocked ή source=blocked το quote widget αποκρύπτεται (δεν έχει νόημα τιμολόγηση σε owner block). Το ίδιο ισχύει όταν απουσιάζουν dates ή check_in >= check_out. Error messages εμφανίζονται inline χωρίς να χαλάει η ροή του form
Αν ο ίδιος κανόνας (π.χ. "Σαββατοκύριακα +20%") εφαρμοστεί σε 3 νύχτες, εμφανίζεται μια φορά με sum των deltas + "3 νύχτες" χαρακτηρισμός. Για LOS/last-minute εμφανίζεται "σε όλο το σύνολο". Tα % operations δεν compound — βασίζονται στο base_rate (per night) ή στο subtotal (per booking)
Math.max(0) clamp για να μην βγει αρνητική τιμή από aggressive subtract, days_until_checkin για last_minute rules υπολογίζεται σε ολόκληρες ημέρες UTC, weekdays array 0=Sun..6=Sat όπως Postgres. Seasonal ranges είναι inclusive [start_date, end_date]
20 Απριλίου 2026
PMS — Auto-προγραμματισμός καθαρισμού όταν έρχεται check-out
Νέο hourly cron (/api/cron/pms-auto-tasks) που σκανάρει κρατήσεις με check-out τις επόμενες 14 ημέρες και δημιουργεί pending task καθαρισμού με τίτλο "Cleaning — <guest> checkout". Idempotency: δεν διπλοδημιουργεί αν υπάρχει ήδη task τύπου cleaning για το ίδιο booking
Scheduled_at = check_out date στην ώρα checkout_time του owner. Αν ο owner θέλει ο καθαριστής να έρχεται πιο νωρίς, ορίζει cleaning_lead_days=1 και το task προγραμματίζεται την προηγούμενη. Default: 0 (ίδια μέρα, ίδια ώρα με check-out)
Νέα πεδία στο pms_owner_settings: cleaning_default_assignee_name/phone/email + cleaning_default_cost. Κάθε auto task έρχεται προ-συμπληρωμένο. Αλλαγές γίνονται πάντα χειροκίνητα στο detail page του task (π.χ. override για συγκεκριμένη κράτηση)
Νέα ενότητα στο /dashboard/pms/settings με toggle auto_cleaning_enabled. Όταν OFF, ο cron παραλείπει τον owner. Όταν ON, εμφανίζονται και τα assignee/cost/lead-days fields για customization. Opt-in by default (μην σπάσουμε υπάρχουσες workflows)
Κρατήσεις με status=cancelled ή blocked δεν λαμβάνουν auto-task. Έτσι ακυρώσεις τελευταίας στιγμής δεν αφήνουν task να εμφανιστεί στα Pending. Όταν μια κράτηση μετακινηθεί σε νέα ημερομηνία, επόμενος cron run δημιουργεί νέο task (αν δεν υπάρχει ήδη)
Τρέχει στο :41 κάθε ώρας (vercel.json). Ξεχωριστό από το pms-dispatch (:29) ώστε spikes να μην επηρεάζουν email sends. Service client για να δουλεύει cross-owner χωρίς auth context
Προσθέτει 6 στήλες στο pms_owner_settings: auto_cleaning_enabled, cleaning_default_assignee_name/phone/email, cleaning_default_cost (NUMERIC), cleaning_lead_days (INT 0-7). RLS μένει το υπάρχον "owner manages own settings" — δεν χρειάζεται νέο policy
20 Απριλίου 2026
PMS — Template Dispatch Engine: αυτόματα emails με triggers & {{variables}}
Νέο hourly cron (/api/cron/pms-dispatch) σκανάρει όλα τα active non-manual templates και στέλνει email όπου ταιριάζει booking: on_inquiry/on_book/on_cancel (με βάση status), 3/1 days before check-in, on_checkin, on_checkout, 7 days after. Καλείται από Vercel Cron στο λεπτό :29 κάθε ώρας
Κάθε template γίνεται render με guest_name, listing_name, check_in, check_out, nights, total, owner_name, owner_phone, owner_email. Η γλώσσα επιλέγεται από guest_country (GR/CY→el, DE/AT/CH→de, FR/BE/LU→fr, IT→it, ES/MX/AR→es, αλλιώς en), με fallback EN → EL → οποιοδήποτε locale έχει content
Το dispatch engine ελέγχει αν υπάρχει ήδη message με ίδιο template_id + booking_id και skipάρει. Έτσι cron runs κάθε ώρα χωρίς κίνδυνο διπλού email. Force re-send επιτρέπεται με flag για edge cases (manual override)
Χρησιμοποιεί το ίδιο Gmail account με το password-reset flow (site_settings.gmail_address + gmail_app_password). Reply-to γεμίζει από pms_owner_settings.reply_to_email ή owner email, ώστε απαντήσεις guest να φτάνουν στον owner όχι στο system inbox
Νέα section στο /dashboard/pms/messages/[id] όταν το thread έχει booking: λίστα όλων των templates που ταιριάζουν στο listing, preview subject+body με συμπληρωμένες variables, Send button ανά template. Έλεγχος γλώσσας, inline override (UI-only preview), "Εστάλη" badge + Re-send option
Endpoint για manual send από UI. Verifyει RLS-scoped ότι template + booking ανήκουν στον caller, φορτώνει listing + owner profile, και delegates στο shared dispatchTemplateToBooking lib. Service client μόνο για site_settings read + cross-policy pms_messages insert
Κάθε template send γράφεται σαν κανονικό outbound message στο pms_messages (channel=email, is_automated=true, template_id FK). Βλέπεις στο thread view τα auto emails με "Auto" badge δίπλα στο channel pill, ώστε να ξέρεις ακριβώς τι ειπώθηκε και πότε
19 Απριλίου 2026
PMS Finance — Revenue, ADR & Occupancy Dashboard
Year + listing filter → 4 KPI cards: Έσοδα (year-over-year delta σε % πάνω στην κάρτα), ADR (Average Daily Rate, €/νύχτα), Occupancy (πληρότητα %), Νύχτες booked (+ σύνολο κρατήσεων). Όλα υπολογίζονται από τα pms_bookings εξαιρώντας ακυρωμένα & blocked dates
12 μήνες σε horizontal bars με gradient emerald→teal, scaled στο max μήνα, με τιμή αριστερά και €amount δεξιά σε tabular-nums. Fast visual για το peak/off-season σου. Προσοχή: αν μια κράτηση πατά δύο μήνες, το nightly amount σπάει ανά ημέρα στον σωστό μήνα (όχι όλο στον checkout month)
Κατάλογος καταλυμάτων sorted by revenue desc, κάθε κάρτα: revenue € + bar (% του totalYear) + κρατήσεις + νύχτες + ADR. Βλέπεις ποιο κατάλυμα είναι star performer και ποιο underperforms — χωρίς να κοιτάς spreadsheets
Ανά source (Direct, Airbnb, Booking.com, VRBO, Manual, Other) με χρωματιστό pill + revenue + bar + % του συνολικού έτους. Βλέπεις άμεσα πόσο OTA commission αποφεύγεις μέσω direct — key motivator για marketing investment
Όταν υπάρχουν bookings με payment_status ≠ fully_paid (και όχι refunded/cancelled), εμφανίζεται amber alert με το σύνολο που οφείλεται. Quick reminder να βγάζεις invoices ή να χάκες reminders
Nightly equivalent = total_amount / booking_nights αν υπάρχει total, αλλιώς nightly_rate. Clip στα όρια του έτους για μετακινήσεις Δεκ→Ιαν. Occupancy = nights / (days_up_to_today × listings_count) × 100 — δεν τιμωρείται για μελλοντικές ημέρες που δεν έχει φτάσει ακόμη η χρονιά
Κάτω από το revenue KPI εμφανίζεται +15.2% vs πέρυσι (emerald) ή -8% (rose) όταν υπάρχει πέρυσι data στο ίδιο scope (listing filter + calendar year). Είναι το νούμερο που ρωτάς πρώτο στα end-of-year reviews
19 Απριλίου 2026
PMS Automations — Message Templates σε 6 Γλώσσες με Triggers
Όλα τα templates σε κάρτες με trigger icon + name + trigger pill + Active/Paused badge + body preview 120 χαρακτήρες + locale codes (EL · EN · DE…) + scope (Όλα τα καταλύματα ή N specific). Paused templates εμφανίζονται σε opacity 75% για να διακρίνονται
Manual (on-demand insertion σε thread), On inquiry (πρώτο guest message), On booking (confirmation), 3 days before / 1 day before (prep reminders), On check-in (welcome), On check-out (thank-you), 7 days after (review request), On cancel. Radio cards με icon + one-line περιγραφή
EL 🇬🇷 · EN 🇬🇧 · DE 🇩🇪 · FR 🇫🇷 · IT 🇮🇹 · ES 🇪🇸 — κάθε locale tab δείχνει αν έχει content με πράσινο check. Subject + body per locale, αποθηκεύονται σε JSONB columns (subject_locales, body_locales) ώστε να στέλνεται το σωστό στη γλώσσα του guest χωρίς κόπο
{{guest_name}}, {{listing_name}}, {{check_in}}, {{check_out}}, {{nights}}, {{total}}, {{owner_name}}, {{owner_phone}} — tap σε variable chip για αυτόματη αντιγραφή στο clipboard. Θα γίνεται substitution την ώρα της αποστολής (render step δεν υλοποιημένο ακόμη)
Toggle buttons "Όλα τα καταλύματα" vs "Επιλεγμένα" — αν specific, checkboxes για κάθε κατάλυμα του owner. Αποθηκεύεται ως UUID[] (null = όλα, array = specific). Για απλά portfolios το "όλα" είναι one-click setup
Templates (σύνολο), Ενεργά, Γλώσσες (μοναδικές locales με content). Pause toggle για εποχική παύση (π.χ. winter rates) χωρίς διαγραφή. Filter bar: trigger dropdown + status (All/Active/Paused) + live search σε name + όλα τα locale bodies
4 sections: Basics (name + active), Trigger (9 radio cards), Content (6 locale tabs + subject + body + variables), Scope (all vs specific + checkboxes). Create/edit share the same form, delete with confirm στο edit page
19 Απριλίου 2026
PMS Messages — Ενοποιημένο Inbox με Threads ανά Κράτηση
Όλα τα μηνύματα ομαδοποιούνται σε threads — ένα ανά κράτηση, ή ανά guest_email όταν δεν υπάρχει κράτηση. Κάθε thread κάρτα: avatar με αρχικό γράμματος guest, όνομα + channel pill + "Auto" badge για templates + unread counter, subject, body preview 140 char, listing name + message count, relative timestamp (τώρα/5λ πριν/3ώ πριν/18 Απρ)
Threads (ομαδοποιημένες συνομιλίες), Αδιάβαστα (inbound χωρίς read_at), Σύνολο μηνυμάτων (όλα τα records)
Direct (slate), Email (sky), WhatsApp (emerald), Airbnb (rose), Booking.com (indigo), System (violet) — βοηθάει να εντοπίζεις με μια ματιά από πού ήρθε το μήνυμα. Φιλτράρισμα ανά channel + listing + live search σε guest/subject/body
Chat-style bubbles — εξερχόμενα δεξιά (violet), εισερχόμενα αριστερά (slate), system messages γκρι italic. Auto mark-as-read όταν ανοίγεις το thread. Guest panel στην κορυφή με name/email + link στην κράτηση, threaded συνομιλία σε χρονολογική σειρά, inline reply composer από κάτω
Toggle μεταξύ "Προς guest (εξερχόμενο)" και "Από guest (εισερχόμενο)" — ώστε να μπορείς να καταχωρήσεις ΚΑΙ μηνύματα που έλαβες εξωτερικά (π.χ. από προσωπικό email) στο ίδιο thread. Channel dropdown, optional subject, multi-line body. Auto sets read_at για inbound entries ώστε να μη φαίνονται unread
Διάλεξε listing (required) + optionally κράτηση → αν επιλέξεις booking, το guest name/email γεμίζουν αυτόματα. Support για standalone threads (inquiry που δεν έγινε booking) ή booking-tied threads. Prefill via ?listing_id=&booking_id= για δημιουργία από άλλες σελίδες
Ένα component για reply (compact mode) και για new thread (full mode με subject). Reusable για μελλοντικά integrations — όταν συνδεθούν email/WhatsApp/Airbnb parsers, μόνο η μετά-αποστολή logic θα αλλάξει. Διαγραφή thread συνολικά από το [id] page
19 Απριλίου 2026
PMS Tasks — Καθαρισμοί, Συντήρηση & Ανάθεση σε Συνεργάτες
Όλες οι εργασίες σε κάρτες με date block (μήνας + ημέρα + ώρα), type pill (Καθαρισμός/Συντήρηση/Επιθεώρηση/Κλινοσκεπάσματα/Υποδοχή/Αναχώρηση/Custom), status pill (Εκκρεμεί/Σε εξέλιξη/Ολοκληρωμένη/Ακυρώθηκε/Παραλείφθηκε), overdue badge όταν pending + περασμένη ώρα, assignee name & κόστος στα δεξιά
Σήμερα (εργασίες προγραμματισμένες για σήμερα), Εκκρεμούν (status=pending), Καθυστερημένες (pending + passed scheduled_at — κόκκινο warning), Κόστος μήνα (sum completed tasks του τρέχοντα μήνα)
Listing dropdown, type dropdown (7 τύποι), status dropdown (5 states) + full-text search σε title/assignee/listing name — όλα combinable, instant filtering client-side
/dashboard/pms/tasks/new — WHAT (type radio cards με icons + title + listing + description), WHEN (scheduled datetime + 5 status pills — completed_at field εμφανίζεται μόνο όταν status=completed), WHO (assignee name/phone/email), MONEY (cost σε € + internal notes)
Νέα εργασία ξεκινά με scheduled_at = αύριο 10πμ — sensible default για cleanings/maintenance. Prefill via ?listing_id=&booking_id=&scheduled_at= querystring για αυτόματη δημιουργία από checkout flow στο μέλλον
/dashboard/pms/tasks/[id] — όλα τα πεδία editable, one-click status change, delete με confirm prompt. Shared <TaskForm/> component μεταξύ create & edit. Όταν status→completed, το completed_at γεμίζει αυτόματα με το τώρα αν ήταν κενό
Rose/pink hero gradient, τύποι εργασιών με δικό τους χρωματικό chip, date block γίνεται rose όταν overdue. Status pills είναι buttons στο form (amber pending, sky in-progress, emerald completed, rose cancelled, slate skipped)
19 Απριλίου 2026
PMS Pricing Rules — Seasonal, Weekend, LOS, Last-Minute
Όλοι οι κανόνες σε κάρτες με type icon (Seasonal/Weekend/Long Stay/Last-minute/Custom), Active ή Paused pill, condition summary (date range, weekdays, min nights, days before) και οικονομικό impact σε χρώμα (+prasino πρόσθεση, -kokkino έκπτωση, =ble override, ×portokali multiply)
Seasonal (date range, π.χ. Peak Ιουλ-Αυγ +40%), Weekend (Πα-Κυ +20% με day pills picker), Long Stay (≥7 νύχτες -10%, ≥14 -15%), Last-minute (≤7 μέρες πριν -15%), Custom (όλα τα fields optional για hybrid rules)
Set price (override), Add, Subtract, Multiply — με toggle μεταξύ Percentage (%) ή Absolute (€). Radio cards με icon + περιγραφή για να καταλαβαίνει κανένας τι κάνει ο κανόνας χωρίς εξήγηση
Βλέπεις σε real-time το "Βασική τιμή → Τελική τιμή" με % difference καθώς αλλάζεις amount/operation/unit. Χρωματισμός: emerald αν ανέβασες, rose αν κατέβασες, slate αν ίδια. Χρησιμοποιεί το listing.price_per_night
7 pill buttons (Κυ-Σα) για weekend και custom rules — tap για select/deselect. Αποθηκεύεται ως INT[] στη βάση (0=Κυριακή). Αν πατήσεις όλα τα Σα & Κυ, έχεις κλασικό Σαββατοκύριακο
Priority 0-1000 (default 100) — υψηλότερο νούμερο υπερισχύει όταν επικαλύπτονται κανόνες. Active toggle για pause/resume χωρίς διαγραφή (π.χ. παύση winter rates το καλοκαίρι)
19 Απριλίου 2026
PMS Bookings — Λίστα Κρατήσεων + Manual Entry
Όλες οι κρατήσεις σε κάρτες με dates block, status pill (Ερώτημα/Εκκρεμεί/Επιβεβαιωμένη/Έχει φτάσει/Έφυγε/Ακυρώθηκε), source dot (Direct/Airbnb/Booking/VRBO/Manual), payment pill (Απλήρωτο/Προκαταβολή/Εξοφλημένο), guest info + listing + nights + total amount — sorted με πιο πρόσφατες πάνω
Έρχονται (check-in στις επόμενες 7 μέρες), Τώρα στο κατάλυμα (checked-in guests), Έσοδα μήνα (confirmed + in-stay bookings του τρέχοντα μήνα), Σύνολο (όλες οι ενεργές — εκτός cancelled/blocked)
Status pills (όλα τα 7 state), listing dropdown (όλα τα καταλύματά σου), live search σε guest_name/email/phone. Clear filters button όταν δεν ταιριάζει τίποτα
/dashboard/pms/bookings/new — κατάχωρηση κράτησης που ήρθε τηλεφωνικά, με email ή walk-in. 5 sections: Διαμονή (listing + dates με auto nights count), Επισκέπτης (name/email/phone/country/ενήλικες/παιδιά), Status & Source, Οικονομικά (τιμή × νύχτες + καθαριότητα + φόροι → auto total ή manual override), Σημειώσεις
/dashboard/pms/bookings/[id] — όλα τα πεδία editable, change status με ένα click, delete με confirm prompt. Shared <BookingForm/> component για create & edit paths
Όταν status=blocked ή source=blocked, κρύβονται guest/financials fields και εμφανίζεται μόνο "Αιτία μπλοκαρίσματος" (π.χ. συντήρηση, προσωπική χρήση) — για όταν θες να κλείσεις ημερομηνίες χωρίς guest
5 καταστάσεις: Unpaid (rose), Deposit Paid (amber), Fully Paid (emerald), Refunded (slate), N/A. Χειροκίνητη ενημέρωση μέχρι να ενεργοποιηθεί το Stripe Connect flow
19 Απριλίου 2026
PMS Settings — Φορολογικά, Πολιτικές, Cancellation & Ειδοποιήσεις
ΑΦΜ, ΑΜΑ (Αριθμός Μητρώου Ακινήτου βραχυχρόνιας μίσθωσης ΑΑΔΕ), συντελεστής ΦΠΑ (default 13% τουριστικός), toggle για τουριστικό φόρο με ποσό ανά διανυκτέρευση — όλα αποθηκεύονται στο pms_owner_settings και θα περιλαμβάνονται αυτόματα στα emails επιβεβαίωσης για νόμιμη τιμολόγηση
Instant Book toggle (αν OFF, κάθε κράτηση περνά από έγκριση), ώρες check-in/out, min/max διανυκτερεύσεις, advance notice σε ώρες, preparation days buffer μεταξύ κρατήσεων — defaults που θα κληρονομούν όλα τα καταλύματα (per-listing overrides αργότερα)
Radio cards για Ευέλικτη (24h πριν) / Μέτρια (7 μέρες πριν) / Αυστηρή (no refund) / Custom (δικά σου λόγια με textarea) — θα εμφανίζεται στο public listing και στα emails επιβεβαίωσης κράτησης
Stripe Connect status card (read-only μέχρι να ολοκληρωθεί το OAuth onboarding flow), deposit percentage (default 20%), balance due days before check-in (default 14) — ready για όταν ενεργοποιηθεί direct bookings με 0% commission
Reply-to email για guests (fallback στο account email αν κενό), τηλέφωνο ειδοποιήσεων, SMS toggle (coming soon) — πού να βρίσκουν τον owner οι guests και πού να φτάνουν τα alerts για νέες κρατήσεις
5 κάρτες με ξεχωριστή παλέτα ring+icon (amber tax, sky booking, rose cancellation, emerald payments, violet notifications), sticky save bar σε mobile (fixed bottom) + inline σε desktop, upsert με onConflict: owner_id — single atomic save για όλο το form
19 Απριλίου 2026
Bug Fix — PMS Calendar έδειχνε "Δεν έχεις listings ακόμα"
Το /dashboard/pms/calendar έστελνε select στη column listings.is_active που δεν υπάρχει (το schema έχει status: draft/published/archived) — η Postgres γύριζε 42703 "column does not exist" και η σελίδα έπεφτε στο empty state παρόλο που ο owner είχε καταχωρημένο κατάλυμα. Αλλαγή σε status + error surfacing + fallback link στο /dashboard/listings
19 Απριλίου 2026
PMS Calendar — Ένα Ημερολόγιο ανά Κατάλυμα
Το /dashboard/pms/calendar δεν δείχνει πλέον ένα μόνο ημερολόγιο με dropdown επιλογής καταλύματος — δείχνει ξεχωριστή ενότητα για κάθε κατάλυμα του owner, στοιβαγμένες κάθετα. Κάθε section έχει δικά της feeds, export URL, block-dates, event details — όλα ανεξάρτητα μεταξύ τους
Grid που στοιβάζει σε mobile (feeds panel πάνω, calendar κάτω) και γίνεται side-by-side σε desktop (340px feeds | rest calendar). Το μηνιαίο navigation και το χρωματικό legend είναι shared και sticky στο top
Το deprecated middleware.ts μετονομάστηκε σε src/proxy.ts σύμφωνα με την Next.js 16 convention. Χωρίς αυτό το rename, όλα τα locale-less URLs (/auth/login, /listings, /dashboard) επέστρεφαν 404 — το next-intl locale routing δεν έτρεχε καθόλου. Now back to normal
19 Απριλίου 2026
Bug Fix — Password Reset Email Έβγαζε σε localhost:3000
Το /auth/v1/verify του Supabase αγνοούσε το δικό μας redirect_to (δεν ήταν στο allow-list των Redirect URLs) και έπεφτε πίσω στο project Site URL που ήταν http://localhost:3000 — ο χρήστης κατέληγε σε σελίδα που δεν υπάρχει στο production. Το email link τώρα δείχνει απευθείας στο /auth/reset-password με token_hash και η σελίδα κάνει verifyOtp στο client, χωρίς περάσμα από τον Supabase verify endpoint
19 Απριλίου 2026
Super-Admin — One-Click Password Reset Email per User
Νέο εικονίδιο κλειδιού δίπλα από κάθε χρήστη στο admin users table — ένα κλικ στέλνει στον χρήστη email επαναφοράς κωδικού. Με confirm prompt + loading spinner + activity log entry
Νέο /api/admin/send-password-reset endpoint — δημιουργεί recovery link μέσω Supabase admin API και το στέλνει με το υπάρχον Gmail SMTP. Branded HTML template (teal gradient header, CTA button, fallback link, security note) ίδιου στιλ με τα QR emails
Public landing page όπου καταλήγει ο χρήστης από το email — διαβάζει tokens από το URL hash, κάνει setSession, ζητά νέο κωδικό (≥6 χαρακτήρες, με confirm field), redirect στο login μετά την επιτυχή αλλαγή
18 Απριλίου 2026
Bug Fix — Type Filter Pages Έδειχναν Μόνο τα 50 Πιο Πρόσφατα
Το /listings/type/with-pool (και όλες οι type-filter σελίδες: sea-view, pet-friendly, family, budget, luxury) ζητούσε μόνο 50 καταλύματα — όσα έχουμε πλέον > 50 publishes, τα παλαιότερα κόβονταν ΠΡΙΝ εφαρμοστεί το client-side φίλτρο. Αποτέλεσμα: καταλύματα με πισίνα σαν το Thespis Villa 2 λείπανε. Αφαιρέθηκε το limit για να ταιριάζει με τη συμπεριφορά του /listings
17 Απριλίου 2026
Free Social Media Kit Auto-Generator per Listing
Νέα σελίδα /dashboard/listings/[id]/social-kit — ο owner κατεβάζει με ένα κλικ ZIP με 3 έτοιμα γραφιστικά (Instagram Square 1080×1080, Instagram Story 1080×1920, Facebook/X Card 1200×630) φτιαγμένα από τη cover + title + tagline + location του καταλύματος
Κάθε εικόνα περιέχει branded QR code που δείχνει στη σελίδα του listing (/listings/[slug]) — όποιος το σκανάρει πάει κατευθείαν στην κράτηση
Έτοιμο ελληνικό κείμενο με emojis, hashtags (#Halkidiki #ChalkidikiHub #VisitGreece) + copy button — για γρήγορο share χωρίς να γράφει τίποτα ο owner
Lazy-loaded JSZip φτιάχνει client-side το ZIP με τα 3 PNGs + README.txt που έχει filenames, dimensions, platform mapping και το caption
/api/social-kit/[format] τρέχει σε edge με next/og ImageResponse — base64-embedded cover + QR (api.qrserver.com), όχι Node-only APIs. 5-10 min browser cache για γρήγορο preview
3-step modal (Welcome → 3 formats, 1 click → Γιατί έχει σημασία) + 30s "How it works" + 6 benefit tiles + FAQ accordion + bottom CTA — explains γιατί αξίζει χωρίς jargon
Νέο pink-rose gradient κουμπί "Social Kit" δίπλα στο QR button σε κάθε listing card — όχι κρυμμένο σε menu
17 Απριλίου 2026
Owner UX Overhaul + Analytics Beta + Clean Translation Split
Cards με cover thumbnail, Ενεργό/Κλειστό pill, labeled action bar (Στοιχεία, Site, Ημερολόγιο, QR, Στατιστικά), search + status pills με live counts
Full-width dismissible promo banner + purple→fuchsia gradient button "QR για επισκέπτες" με pulsing amber dot — αντικαθιστά το invisible icon
Owners γράφουν μόνο ελληνικά. Αφαιρέθηκαν ~540 γραμμές AI translation UI από FaqsEditor, EmergencyContactsEditor, HouseRulesEditor, PracticalInfoEditor, ExtrasEditor, PhotoCaptionsEditor, ClosedStateEditor + brand page
13 multilingual fields × 7 locales = 91 cells σε ένα side-by-side editor: title, description, tagline, owner_story, closed_reason, house_rules_extra, how_to_reach, wifi_info, parking_info, check_in_info, meta_title, meta_description, image_alt
/dashboard/listings/[id]/analytics με seeded deterministic demo data: 30-day sparkline (inline SVG), country/source/language breakdown, click actions ranking, stat cards με period deltas
Αφαιρέθηκαν "Ημερολόγια" + "Φτιάξε το site σου" από owner menu — όλα accessible από cards, λιγότερα menu items
select("*") pattern στο my-listings survives schema drift — αν λείπει column, το page δεν σκάει, δείχνει error banner με hint
image_alt_{7 locales} στο listings table + backfill του single image_alt στο image_alt_el
17 Απριλίου 2026
Temporarily Closed Flag per Listing
Owners μπορούν να κλείσουν προσωρινά το κατάλυμα (σεζόν, ανακαίνιση, προσωπικοί λόγοι) χωρίς να το διαγράψουν ή να κάνουν unpublish
Optional ημερομηνία επαναλειτουργίας + αιτιολογία (π.χ. "Ανακαίνιση — επανερχόμαστε Απρίλιο 2026") σε 7 γλώσσες
Amber-to-orange gradient banner στην κορυφή της σελίδας όταν το κατάλυμα είναι κλειστό — contact buttons παραμένουν για μελλοντικές κρατήσεις
Visible chip στο /dashboard/listings cards, site-builder hub, admin brand-sites — καθαρή διάκριση από draft/published status
listings.is_closed (boolean, default false) + listings.reopening_date + closed_reason_{7 locales}
17 Απριλίου 2026
Admin Brand Sites Manager + Multilingual Editor + SEO Generator
Super-admin βλέπει όλα τα brand pages: coverage badges ανά γλώσσα (x/7), completeness score 0–6, search + area filter, counts για FAQs / Emergency / Extras / Captions
Νέο MultilangField component: tabs ανά γλώσσα με ✓ checkmark όταν έχει content, coverage x/7, per-field "Fill missing" button που γεμίζει ελλείπουσες γλώσσες με AI
Ένα κλικ περπατάει όλα τα fields × 6 locales και γεμίζει ελλείπουσες μεταφράσεις από EL ή EN fallback — 54+ translations σε ένα save
Νέο /api/ai/generate-seo endpoint: GPT-4o-mini παράγει meta_title (55-60 chars) + meta_description (140-160 chars) σε όλες τις 7 γλώσσες — benefit-focused, preserves proper nouns
Super-admin στο /dashboard/site-builder βλέπει πλέον ΟΛΑ τα καταλύματα (όχι μόνο τα δικά του) με violet "Admin mode" banner + owner email chip σε κάθε card
17 Απριλίου 2026
House Rules + Practical Info + Extras + Photo Captions + Nearby Overrides
Check-in/out times, κάπνισμα (allowed/outside/no), κατοικίδια (allowed/on_request/no), πάρτι, παιδιά, ώρες κοινής ησυχίας + free-text extras. Pill-button selectors για κάθε κανόνα
4 textareas: Πώς θα φτάσετε, Οδηγίες check-in, Wi-Fi, Στάθμευση. Εμφανίζονται σε 2×2 grid cards στο /stay page
Unlimited add-ons με 9 icon types (Πρωινό, Μεταφορά, Καθαριότητα, Ποδήλατο, Σκάφος, Spa κ.λπ.), τιμή + μονάδα (ανά διαμονή/βράδυ/άτομο/χρήση) ή "Περιλαμβάνεται δωρεάν"
Λεζάντες ανά φωτογραφία, εμφανίζονται σε hover overlay στη gallery του /stay. Helps SEO alt text + guest context
Auto-computed λίστα κοντινών παραλιών/εστιατορίων/δραστηριοτήτων/χωριών με Haversine. Owner μπορεί να hide/unhide individual items
listings.check_in_time, rule_*, quiet_hours_*, house_rules_extra_{7}, how_to_reach_{7}, wifi_info_{7}, parking_info_{7}, check_in_info_{7} + listing_images.caption_{7} + new listing_extras table
17 Απριλίου 2026
FAQs CRUD + Emergency Contacts + Legal Compliance
Owners προσθέτουν custom Q&A — inline FAQPage microdata (Schema.org Question/Answer) στο /stay → Google rich results με expandable FAQ carousel στα SERP
6 default ΕΕ/Ελλάδας numbers εμφανίζονται ΠΑΝΤΑ (112, 100 Αστυνομία, 166 ΕΚΑΒ, 199 Πυροσβεστική, 108 Λιμενικό, 10135 Δηλητηριάσεις) + owner adds τοπικές επαφές
Amber info banner στον editor: "Σύμφωνα με Ν. 4276/2014 (τουριστικά καταλύματα), Ν. 4179/2013, κανονισμούς πυρασφάλειας…" — καλή πρακτική για βραχυχρόνιες μισθώσεις
Κάθε τηλέφωνο είναι <a href="tel:…"> — ο guest πατάει και καλεί κατευθείαν από το κινητό του
listing_emergency_contacts table: icon_key (10 types), phone, label_{7 locales}, notes_{7 locales}. RLS: public SELECT, owner/admin write
17 Απριλίου 2026
Dedicated /stay/[slug] Brand Page
Κάθε κατάλυμα αποκτά δική του full-bleed σελίδα στο /stay/[slug], τελείως διαφορετική εμπειρία από το απλό /listings/[slug] directory entry
70vh full-width cover image, italic tagline, sticky facts bar (guests · beds · baths · price), contact CTAs (WhatsApp, phone, email)
Sections με ιεραρχία: Our Story (gradient centered) → Gallery → Description → Amenities → What's Nearby → Map → Availability → FAQs → Contact CTA → Emergency
/stay/{slug} URLs εμφανίζονται στο sitemap ΜΟΝΟ όταν ο owner έχει γράψει tagline ή story — αποφεύγει duplicate content με /listings
Gradient pill "Δείτε το site του καταλύματος →" στο /listings όταν το listing έχει brand content
17 Απριλίου 2026
Brand Page Tier-1: Tagline, Our Story, Auto Nearby, FAQs Display
Μικρή φράση (~80 chars) κάτω από τον τίτλο του καταλύματος. Είναι το πρώτο πράγμα που τραβά το μάτι του επισκέπτη
Προσωπική αφήγηση του owner για το κατάλυμα (gradient card). Differentiator που κανένα listing site δεν προσφέρει
Haversine distance calculation με lat/lng bounding box — εμφανίζει nearest παραλίες, εστιατόρια, δραστηριότητες, χωριά με αποστάσεις σε km/m
Νέο /api/nearby?listing_id=X — returns grouped results, respects owner overrides (hidden items + custom notes)
Accordion με FAQPage JSON-LD στο /stay. CRUD editor έρχεται στο v3.8
Generic /api/ai/translate-fields endpoint: send {sourceLocale, fields: {name: text…}}, get back 6-locale translations per field. GPT-4o-mini με JSON response format
listings.tagline_{7} + owner_story_{7} + listing_faqs table + listing_nearby_overrides table (owner can hide/reorder auto-suggestions)
17 Απριλίου 2026
Calendars Hub + Public Visibility Toggle
Dashboard → Ημερολόγια → βλέπεις όλα τα καταλύματα σου με blocked-days counter ανά κατάλυμα
Eye/EyeOff toggle per listing — default OFF (safe for existing listings), owner opt-in. Ελέγχει αν το calendar εμφανίζεται στο /listings directory page
Στην προσωπική σελίδα /stay/[slug] το calendar εμφανίζεται ΠΑΝΤΑ — το toggle αφορά μόνο το directory listing
listings.show_calendar boolean NOT NULL DEFAULT false
17 Απριλίου 2026
Availability Calendar για Listings
3-month grid με click-to-toggle: 🟠 Μπλοκαρισμένη, 🔴 Κρατημένη, 🟢 Διαθέσιμη. Batch save με pending-changes counter, bulk clear all, past dates disabled, today highlighted
2-month read-only view στο listing page — άσπρα cells = διαθέσιμη, κόκκινα = μη διαθέσιμη. Localized month/day names για όλες τις 7 γλώσσες
Responsive grid, touch-friendly buttons, active:scale-98 feedback
listing_availability table με public read + owner/admin write policies — RLS ελέγχει ότι δεν πειράζει κανένας κάποιο άλλο listing
Νέα listing_availability table με (listing_id, date, status ∈ {blocked,booked}, note). Unique (listing_id, date), auto-updated timestamps
17 Απριλίου 2026
9 Νέοι SEO Hook Guides: Comparisons + Niche + Practical Tips
Σύγκριση με την Κρήτη: παραλίες, πρόσβαση, κόστος, φαγητό, ποιος νικάει. Target: "Halkidiki vs Crete" keyword
Σύγκριση με τη Ρόδο — ιστορία, παραλίες, κλίμα, κόστος διαμονής
Ιόνιο vs Αιγαίο — climate, beaches, access, Venetian architecture
Guide για ηλικιωμένους: εύκολη πρόσβαση, ήρεμες παραλίες, ιατρικές υπηρεσίες, all-inclusive resorts
Πέρα από honeymoon — ρομαντικές παραλίες, δείπνα με θέα, ιδανική περίοδος (Μάιος/Σεπτέμβριος)
Ασφάλεια, μεταφορές KTEL, social spots, budget €60-100/μέρα, πού να μείνεις
20+ insider tips: booking timing, beaches, food, exploration, practical — με εσωτερικούς συνδέσμους σε /guide/*
Συχνά λάθη τουριστών (last-minute booking, only Kassandra, tourist trap restaurants, no cash)
Taxi meter, menu χωρίς τιμές, "free" loungers, DCC σε κάρτες, fake "τοπικό" λάδι — πώς να προστατευτείς
9 guides × 7 γλώσσες στο sitemap. Όλα με Article + BreadcrumbList JSON-LD + εσωτερικά links
17 Απριλίου 2026
SEO Hook Pages Expansion: +126 Travel / Itinerary / Cost URLs
8 νέες σελίδες: από Σόφια, Βουκουρέστι, Βελιγράδι, Θεσσαλονίκη, Μόναχο, Κωνσταντινούπολη, Σκόπια, Αθήνα. Πλούσιο περιεχόμενο με internal links, χρόνοι διαδρομής, συμβουλές
5 μέρες, 7 μέρες, 10 μέρες, 3 μέρες, weekend — detailed day-by-day planning με εσωτερικούς συνδέσμους σε beaches/restaurants/villages
5 budget guides: daily budget, food prices, accommodation prices, car rental prices, family budget — πραγματικές τιμές για Χαλκιδική 2026
Κάθε νέα σελίδα έχει 2-4 internal links προς beaches / restaurants / activities / villages / άλλους guides → traffic funneling στο κεντρικό site
18 slugs × 7 γλώσσες = 126 νέα sitemap entries με Article + BreadcrumbList JSON-LD
Redesigned villages grid στο /areas για mobile (uniform 2-column cards), new /places index page, ItemList JSON-LD για rich results, Mega.webp orphan removed
14 Απριλίου 2026
Performance Overhaul, Keyword SEO Articles, Smart Search, Auth Fix
Όλες οι σελίδες (collection + detail) φορτώνουν server-side — zero skeleton flash, 10x γρηγορότερο πρώτο load
Όλα τα cards + blog images χρησιμοποιούν next/image — auto WebP/AVIF, responsive srcSet, 60% μικρότερα αρχεία
Νέο /api/revalidate — admin save → instant cache purge σε 7 γλώσσες. ISR 1 ώρα + on-demand = 95% λιγότερα writes
571+ restaurants, 100+ beaches, 70+ activities pre-built στο deploy — zero latency στο πρώτο visit
Νέο /api/search — GlobalSearch κάνει 1 debounced call αντί 5 full-data fetches. -70% bandwidth
Detail pages κάνουν 1 fetch αντί 3-4 — /api/related-content endpoint. -200-400ms ανά σελίδα
Google Analytics/AdSense χρησιμοποιούν next/script lazyOnload αντί blocking <script> tags
Generator 20 θεματικών articles γύρω από bold keywords χωριών — 246 keywords → auto internal links
Batch translation (2 γλώσσες/κλήση × 3 batches) — δεν σκάει σε μεγάλα κείμενα + progress indicator
requireSuperAdmin() χρησιμοποιεί @supabase/ssr αντί manual cookie parsing — φτιάχνει delete user, send email, reviews
Όλα τα 6 AI routes: auto-retry, rate limit handling (429), empty response validation
Preconnect + dns-prefetch για OpenStreetMap tiles — πιο γρήγοροι χάρτες
ISR revalidate 60s → 3600s — μείωση 95% ISR writes (171K/200K → ~5K/μήνα)
/api/chargers?slug=X — fetch μόνο 1 charger αντί όλους
ImageGallery modal image χρησιμοποιεί loading="lazy"
12 Απριλίου 2026
SEO Overhaul, Dynamic OG Images, Google AdSense, Airbnb Import
OG images, metadata σε όλες τις σελίδες, breadcrumbs, split sitemap, canonical URLs
Αυτόματα generated Open Graph images ανά σελίδα για social sharing
Ενσωμάτωση Google AdSense (ca-pub-9694572418424066) + ads.txt
Import listings από Airbnb/Booking URL στο admin — auto-parse τίτλο, φωτό, amenities
SR tabs σε blog edit, title/excerpt/content/SEO translations
AI blog articles ανά χωριό + Beach Article Generator ανά παραλία
Auto-linking λειτουργεί και σε HTML blog articles (όχι μόνο markdown)
Μετάφραση 25+ αρχείων hardcoded text σε 7 γλώσσες
Αλλαγή 307→308 permanent redirects για καλύτερο SEO
Αναζήτηση + φίλτρα σε beaches, restaurants, activities, blog admin pages
Article generators σπασμένοι σε 2 βήματα — αποφεύγουν Vercel timeout
11 Απριλίου 2026
Serbian Language, Hero Image, Full SEO Audit, 4,000+ URLs
Πλήρης υποστήριξη Σερβικών: UI, DB columns, AI translations, SEO meta, sitemap — 573 νέα URLs
Ρυθμιζόμενη background εικόνα στο hero section της αρχικής σελίδας μέσω admin Settings
Hreflang 7 γλωσσών σε ΟΛΕΣ τις σελίδες, canonical URLs, meta titles σε SR, terms/privacy/map metadata
Πλήρης μετάφραση οδηγού Αγίου Όρους στα Σερβικά — 8 σελίδες + 20 μονές
AI Auto-Complete, Bulk Fill, Auto-Blog — όλα υποστηρίζουν 7 γλώσσες + undefined guard
573 σελίδες × 7 γλώσσες = 4,011 URLs στο sitemap, 0 errors
10 Απριλίου 2026
Seasonal Guides, Listing Types, Broken Links Scanner, Blog Fix
7 θεματικοί οδηγοί (summer, easter, honeymoon, families, budget, winter, nightlife) × 6 γλώσσες = 42 URLs
6 τύποι καταλυμάτων (pool, sea-view, pet-friendly, family, budget, luxury) × 6 γλώσσες = 36 URLs
Νέο εργαλείο στο admin — σκανάρει εσωτερικούς links σε όλο το content, βρίσκει broken
AI articles τώρα renderάρονται σωστά με HTML formatting αντί raw tags
Κάθε κλικ = διαφορετικό άρθρο (topic rotation βάσει count), Unsplash photos
10 Απριλίου 2026
Best Of Guides, Auto-Blog Settings, Unsplash Photos
12 οδηγοί (beaches, restaurants, activities per area/theme) × 6 γλώσσες = 72 SEO URLs
On/Off, συχνότητα (ώρες), ώρα εκτέλεσης — ρυθμιζόμενα από admin Settings
AI articles αυτόματα βρίσκουν σχετική φωτογραφία μέσω Unsplash API
AI articles με h2/h3/lists/blockquote/bold — travel blog style
Auto-blog auth μέσω Bearer token + admin client role check
10 Απριλίου 2026
Auto-Blog AI, Beach Features, Village Combos, 3,300 SEO URLs
AI γράφει 1 άρθρο/ημέρα αυτόματα — 14 rotating topics, πραγματικά data, 6 γλώσσες, SEO, δημοσίευση
12 χαρακτηριστικά παραλιών (sandy, organized, nudist κλπ) × 6 γλώσσες = 72 SEO URLs
68 χωριά × 3 types (beaches/restaurants/activities) × 6 γλώσσες = 1,224 SEO URLs
Κάθε area page δείχνει τα χωριά της ως clickable pills με πληθυσμό
Σύνολο σελίδων στο sitemap — 0 errors σε full crawl
10 Απριλίου 2026
Sun & Sea Logo, Monastery Images, Brand Identity
Νέο brand logo — ήλιος + κύματα σε cyan φόντο. Εφαρμογή σε header, footer, favicon, PWA manifest
Κάθε μονή δείχνει φωτογραφία στο hero + full image section στη σελίδα της
Reusable BrandIcon component, updated theme-color #0891B2, SVG favicons
10 Απριλίου 2026
Monastery Admin, Village Filters, Security Hardening, 68 Villages
Επεξεργασία μονών Αγίου Όρους: 6 γλώσσες, AI Generate description + highlights, AI Auto-Complete SEO
29 νέα χωριά Ενδοχώρας — Πολύγυρος, Αρναία, Ολυμπιάδα, Γερακινή κ.α. Σύνολο 408 SEO URLs
Αναζήτηση, φίλτρα (area, image, SEO, population), sortable columns, stats bar
Auth checks σε όλα τα admin API, input validation, XSS sanitization, service role key protection
Sitemap ISR, map page limits, comments/inquiry caching
Κάθε μονή δική της σελίδα — 120 SEO URLs, prev/next navigation, JSON-LD, 6 γλώσσες
10 Απριλίου 2026
Mount Athos Guide, 6-Language Translations, Area Banner
8 σελίδες: μοναστήρια, κανόνες, μεταφορές, διαμονή, ζωή, πεζοπορία, ιστορία — πλήρης μετάφραση 6 γλωσσών
8 σελίδες × 6 γλώσσες με meta titles, descriptions, hreflang, JSON-LD schemas
Ωραίο banner στη σελίδα /areas/athos που οδηγεί στον πλήρη οδηγό Αγίου Όρους
TouristAttraction, Article, FAQPage, ItemList — πλούσια δεδομένα για Google
10 Απριλίου 2026
Live Weather, AI Formatted Descriptions, SEO Tools Update
Τρέχων καιρός (θερμοκρασία + icon) στο hero κάθε χωριού μέσω OpenWeatherMap
Το AI Generate γράφει μορφοποιημένο HTML (headings, lists, bold) για ωραία ανάγνωση
Τα χωριά συμπεριλαμβάνονται σε Quality Checker, Translation Matrix, SEO Dashboard, AI Bulk SEO
Κασσάνδρα (18), Σιθωνία (15), Άθως (6) — σωστή λίστα με νέα χωριά
10 Απριλίου 2026
Village Pages, Admin Restructure, Footer Upgrade
Σελίδα ανά χωριό Χαλκιδικής — Κασσάνδρα (18), Σιθωνία (15), Άθως (6) με κοντινές παραλίες, εστιατόρια, δραστηριότητες
Αυτόματη δημιουργία περιγραφής + πληθυσμού ανά χωριό μέσω AI
Πλήρης διαχείριση χωριών: New/Edit/Delete + AI Auto-Complete σε 6 γλώσσες + SEO
39 χωριά × 6 γλώσσες = 234 νέες σελίδες στο sitemap για Google indexing
"Γιατί ChalkidikiHub;" section + CTA card + Chalkidiki Sales link στο footer
Τα preview links σε beaches, restaurants, activities, blog, sales ανοίγουν σωστά με locale
9 Απριλίου 2026
Admin & Dashboard Redesign, Translation Matrix, Quality Checker
7 ξεκάθαρα sections αντί για 5 — Places, Properties, Editorial, Moderation, Data & Media, System
SEO Health, Translation Coverage, Action Required banners, Recent Activity feed
Νέα σελίδα — matrix 159 items × 6 γλώσσες με AI Fill button
Νέα σελίδα — σκανάρει όλο το περιεχόμενο, εντοπίζει missing translations, SEO, images
Κουμπί Preview σε κάθε admin list (beaches, restaurants, activities, blog, sales)
Welcome message, Sales stats, compact quick actions, collapsible inquiries
"Γιατί ChalkidikiHub;" section + CTA card + Chalkidiki Sales link
Pending reviews badge count στο admin sidebar
9 Απριλίου 2026
Sales Section, SEO Ghost Pages, Admin Edit
Ολοκληρωμένο section πωλήσεων — κατοικίες, διαμερίσματα, γη, επαγγελματικά χώροι
Ανεξάρτητη αρχική, header, footer με emerald branding για τις πωλήσεις
Επεξεργασία ακινήτων σε 6 γλώσσες + AI Auto-Complete + AI Format
Πλήρης μετάφραση sales section σε EL, EN, DE, BG, RU, RO
Κρυφές σελίδες ανά περιοχή/κατηγορία — μόνο στο sitemap για Google ranking
SEO σελίδες ανά τύπο εστιατορίου (/restaurants/category/[type])
Χρήστες δημιουργούν/διαχειρίζονται τις αγγελίες τους
Publish/unpublish, delete, edit ακινήτων από admin panel
Hero, carousel, property types, οδηγίες καταχώρησης, "Τι κάνουμε στο παρασκήνιο"
8 Απριλίου 2026
Dynamic Business Types, Google Import Activities
Οι κατηγορίες εστιατορίων αποθηκεύονται στη DB — ο admin προσθέτει νέες χωρίς κώδικα
Μετάφραση κατηγοριών σε 6 γλώσσες με ένα κλικ
Import δραστηριοτήτων από Google Places API με φωτογραφίες + AI περιγραφή
8 Απριλίου 2026
Performance Optimization, Image Compression
Όλα τα API calls έχουν πλέον ?limit= — ~80% μείωση μεταφοράς δεδομένων
Αυτόματη συμπίεση εικόνων κατά το upload
Επιλογή φωτογραφιών + AI περιγραφή στο Google Import εστιατορίων
Επιλογή περιοχής κατά το Google Import
7 Απριλίου 2026
User Reviews, Blog Comments, Performance Boost
Οι χρήστες αφήνουν κριτικές σε παραλίες, εστιατόρια, δραστηριότητες (login required)
Σχόλια κάτω από κάθε blog article με moderation
Εργαλείο ανάλυσης internal links ανά σελίδα + AI βελτίωση αδύναμων σελίδων
Βρίσκει σελίδες χωρίς φωτό → αναζήτηση δωρεάν φωτογραφιών από Unsplash
Bulk import παραλιών, εστιατορίων, δραστηριοτήτων μέσω AI σε 6 γλώσσες
Optimized API calls (~80% λιγότερα data), cache headers, targeted queries
Νέος τύπος κατηγορίας Φαγητό & Ποτό
Honeypot fields + rate limiting σε register, contact, reviews
Ο admin μπορεί να διαγράψει χρήστες (cascading cleanup)
7 Απριλίου 2026
Booking Integration, Mass Email, External Emails
Κάθε κλικ σε Booking.com, Airbnb, Phone, Email καταγράφεται
Fixed bar με τιμή + CTA κουμπί σε mobile listing pages
Inquiry form σε κάθε listing — στέλνει email στον ιδιοκτήτη
Αποστολή emails σε χρήστες — 5 λίστες + εξωτερικά emails
Ιστορικό αποστολών με sent/failed counts
Pending submissions + unread messages alerts στο admin dashboard
Μετονομασία σε "Φαγητό & Ποτό" + νέοι τύποι: Bar, Cocktail Bar, Brunch, Café-Bar, Beach Bar
15 κουμπιά γρήγορης πρόσβασης στο admin dashboard
Dashboard stats στα ελληνικά
7 Απριλίου 2026
QR Guest Guide, Engagement Features, SEO Fixes
Digital concierge — ο πελάτης σκανάρει QR στο δωμάτιο, βλέπει παραλίες, εστιατόρια, τηλέφωνα
Heart icon στο header με αριθμό αγαπημένων
"Είδατε πρόσφατα" strip σε κάθε detail page
Badges σε sidebar για pending submissions + messages
Κουμπί αντιγραφής link σε κάθε σελίδα (Facebook, WhatsApp, Telegram, Email)
Κουμπί "AI Μορφοποίηση" — ξαναγράφει κείμενο σε παραγράφους, τίτλους, bullet points
Εισαγωγή φωτογραφιών μέσα στο κείμενο blog articles
Hamburger menu + drawer navigation σε mobile
4 χρωματιστά CTA cards: Κατάλυμα, Εστιατόριο, Δραστηριότητα, Άρθρο
6 Απριλίου 2026
Full Platform Launch
Καταχώρηση ενοικιαζόμενων δωματίων με φωτογραφίες, χάρτη, amenities
13+ παραλίες Χαλκιδικής με features, rating, crowd estimation
70+ εστιατόρια & beach bars με reviews, τηλέφωνα, ωράρια
Αξιοθέατα, εκδρομές, water sports, πεζοπορία
Άρθρα & οδηγοί με AI auto-linking σε παραλίες, εστιατόρια, δραστηριότητες
Live δεδομένα φορτιστών ηλεκτρικών οχημάτων (Open Charge Map)
Ελληνικά, Αγγλικά, Γερμανικά, Βουλγαρικά, Ρωσικά, Ρουμανικά
Μετάφραση + SEO σε 6 γλώσσες με ένα κλικ (GPT-4o-mini)
Αναζήτηση Greek↔Latin: "σάρτη" = "sarti" = "σαρτι"
Leaflet χάρτες με location picker σε κάθε καταχώρηση
JSON-LD, canonical, hreflang, meta tags, sitemap σε κάθε σελίδα
Χρήστες προτείνουν εστιατόρια, δραστηριότητες, άρθρα → admin moderation
Καταγραφή ενεργειών χρηστών, errors, admin actions
Πλήρες panel: Users, Listings, Content, SEO, Tools, Settings, Email
Progressive Web App — offline support, mobile install
Built with Next.js, Supabase, Tailwind CSS & AI
ChalkidikiHub.gr — Η πλατφόρμα τουρισμού της Χαλκιδικής