Στην παραπάνω αρχιτεκτονική, γύρω από το Laravel API του luxi.gr συνδέονται τέσσερα custom modules. Ένα πέμπτο είναι σε beta: AI Demand Prediction, ένα μοντέλο που προβλέπει ζήτηση ανά ζώνη της Αθήνας, ώστε τα οχήματα να προτοποθετούνται και η τιμολόγηση να προσαρμόζεται σε πραγματικό χρόνο.
Το πρόβλημα, τέσσερα ζητούμενα που δεν λύνονται με plugin
Ο πελάτης ήρθε με μια ιδέα χωρίς όνομα: premium private transfers στην Αθήνα για ταξιδιώτες, στελέχη και VIP πελάτες. Το site ήταν το εύκολο μέρος. Τα τέσσερα ζητούμενα ήταν το δύσκολο.
Πρώτον, δεν υπήρχε όνομα, μόνο η περιγραφή «luxury taxi service». Δεύτερον, ήθελε διαφορετικό αριθμό τηλεφώνου ανά πηγή κίνησης — Google Ads, organic, referral — γιατί αλλιώς δεν υπάρχει τρόπος να ξέρει ποιο κανάλι φέρνει τις κλήσεις που κλείνουν. Τρίτον, ήθελε προστασία του τιμοκαταλόγου: ανταγωνιστές αντιγράφουν τιμές και τις αναρτούν στα δικά τους site λίγο χαμηλότερες. Και τέταρτον, μέτρα απέναντι σε aggregators τύπου Welcome Pickups ή GetTransfer, που κάνουν scraping τιμές για να τις δείξουν σε σύγκριση στα δικά τους κανάλια.
Πάνω από όλα αυτά, η σελίδα έπρεπε να κατατάσσεται για αναζητήσεις όπως «private transfer Athens» και «luxury taxi airport Athens», και να έχει blog με τακτικό περιεχόμενο.
Naming, γιατί luxi
Ξεκινήσαμε με τετράωρο brand positioning workshop. Το κοινό ορίστηκε ως business travelers με υψηλή δαπάνη, VIP και premium τουρισμός, ο ανταγωνισμός ως Welcome Pickups, GetTransfer και οι κλασικές εφαρμογές ταξί, και η υπόσχεση του brand σε μία γραμμή: ο premium πελάτης δεν περιμένει, και δεν πρέπει να διαλέγει ανάμεσα σε ποιότητα και ευκολία.
Η ονοματοδοσία κατέληξε γρήγορα. Το LuxiTaxi ήταν πολύ μακρύ και έδενε το brand σε μια λέξη —«ταξί»— που έπρεπε να αποφύγει. Το LuxTaxi ήταν πολύ κοντά σε υπάρχοντα σήματα. Το luxi είναι σύντομο, προφέρεται καθαρά σε αγγλικά, ελληνικά, γερμανικά και ιταλικά, και θυμάται εύκολα από τον ξένο επισκέπτη. Το κρίσιμο ήταν η διαθεσιμότητα: το luxi.gr ήταν ελεύθερο και κατοχυρώθηκε αμέσως. Το .gr δεν ήταν συμβιβασμός, ήταν επιλογή — ταυτίζει άμεσα την υπηρεσία με την Αθήνα.
Λογότυπο
Το λογότυπο είχε να μεταφέρει τρία πράγματα: κίνηση, γιατί το προϊόν είναι το να μη περιμένεις· premium τοποθέτηση, δηλαδή τίποτα από την αισθητική του κίτρινου ταξί· και αναγνωρισιμότητα σε μικρό μέγεθος, γιατί το πρώτο σημείο επαφής είναι συχνά ένα favicon ή ένα εικονίδιο εφαρμογής.
Παραδώσαμε τρεις σχεδιαστικές κατευθύνσεις σε πέντε εργάσιμες. Επιλέχθηκε το minimal wordmark με σύμβολο που υπονοεί μετακίνηση. Το παραδοτέο περιλάμβανε το λογότυπο σε 17 αρχεία (SVG, PNG, PDF, AI), brand guidelines σε PDF και Figma, χρωματικό σύστημα σε Pantone coated και uncoated μαζί με CMYK, RGB και HEX, και πλήρες σετ favicon, εικονιδίων εφαρμογής και OpenGraph.
Το booking system
Η εφαρμογή είναι Laravel 11 σε PHP 8.3, και το ταμείο είναι το σημείο όπου κρίνεται το 11,4% conversion. Η τιμολόγηση γίνεται σε πραγματικό χρόνο βάσει χάρτη, με τις διαδρομές και τα έξτρα ορατά πριν το τελευταίο βήμα. Το checkout είναι πολλαπλών βημάτων —σημείο παραλαβής, προορισμός, όχημα, έξτρα, στοιχεία επιβάτη, πληρωμή— με Stripe για κάρτες, Apple Pay και Google Pay. Επιβάτης και οδηγός ενημερώνονται με email και SMS, και στο backend υπάρχει πάνελ ανάθεσης οδηγού και ημερολογιακή προβολή για τη διαχείριση.
Διαφορετικό τηλέφωνο ανά κανάλι
Σε αυτή την κατηγορία, ένα μεγάλο κομμάτι των κρατήσεων δεν γίνεται online. Ο πελάτης παίρνει τηλέφωνο. Και αν όλα τα κανάλια δείχνουν τον ίδιο αριθμό, όλη η διαφημιστική δαπάνη αξιολογείται στα τυφλά.
Η υλοποίηση είναι σκόπιμα server-side. Τα δυναμικά τηλέφωνα που μπαίνουν με JavaScript σπάνε σε δύο πολύ συνηθισμένες περιπτώσεις: όταν ο επισκέπτης έχει ad blocker, και όταν η σελίδα διαβάζεται από κάτι που δεν εκτελεί JavaScript. Στον server δεν σπάει ποτέ:
// app/Http/Middleware/AttributeSource.php — η πηγή κολλάει στη συνεδρία
public function handle(Request $request, Closure $next)
{
// Μία φορά ανά συνεδρία: το πρώτο κανάλι είναι εκείνο που πλήρωσε.
if (! $request->session()->has('src')) {
$request->session()->put('src', $this->detect($request));
}
// Ο αριθμός μπαίνει στο HTML από τον server, άρα δεν τον σβήνει κανείς.
view()->share('callNumber', PhonePool::forSource(
$request->session()->get('src')
));
return $next($request);
}
private function detect(Request $r): string
{
return match (true) {
$r->filled('gclid'), $r->query('utm_source') === 'google' => 'google_ads',
$r->query('utm_source') === 'meta' => 'meta',
str_contains($r->headers->get('referer', ''), 'google.') => 'organic',
$r->headers->has('referer') => 'referral',
default => 'direct',
};
}
Το if (! has('src')) είναι η γραμμή που κάνει τη μέτρηση δίκαιη: αν ο επισκέπτης έρθει από διαφήμιση και ξαναγυρίσει αργότερα απευθείας, η κλήση αποδίδεται στο κανάλι που τον έφερε πρώτο, όχι στο τελευταίο κλικ.
Προστασία τιμοκαταλόγου και άμυνα σε aggregators
Σε premium κατηγορία, η σύγκριση τιμών από τρίτους δεν είναι ουδέτερη: μειώνει την αντιληπτή αξία και μετατρέπει την υπηρεσία σε γραμμή σε έναν πίνακα. Οπότε η άμυνα είναι πολυεπίπεδη, με τη λογική ότι κάθε επίπεδο κοστίζει στον scraper περισσότερο από όσο αξίζει το δεδομένο.
Το δεύτερο επίπεδο είναι και το φθηνότερο σε υλοποίηση, και το πιο αποτελεσματικό. Το όριο ρυθμού μπαίνει σε μία δήλωση, και η επιλογή του νούμερου είναι όλη η ουσία: πέντε αιτήματα το λεπτό είναι πολλά για άνθρωπο που υπολογίζει μια διαδρομή, και τίποτα για κάποιον που θέλει να κατεβάσει έναν τιμοκατάλογο.
// app/Providers/AppServiceProvider.php — το pricing endpoint είναι το asset
RateLimiter::for('pricing', function (Request $request) {
// Ο συνδεδεμένος πελάτης δεν πρέπει να ενοχλείται ποτέ.
if ($user = $request->user()) {
return Limit::perMinute(60)->by($user->id);
}
// Ο ανώνυμος: 5 το λεπτό. Άνθρωπος δεν το φτάνει, scraper το χτυπά αμέσως.
return Limit::perMinute(5)->by($request->ip())->response(
// 429 χωρίς λεπτομέρειες: δεν δίνουμε πληροφορία στον απέναντι.
fn () => response()->json(['message' => 'Too many requests'], 429)
);
});
Στο επίπεδο του browser υπάρχει και προστασία από αντιγραφή οθόνης: υδατογράφημα με διεύθυνση IP και χρονοσήμανση πάνω στους τιμοκαταλόγους, και ονόματα κλάσεων CSS που αλλάζουν σε κάθε deploy, ώστε ένας scraper που στηρίχτηκε σε selectors να σπάει μόνος του. Δεν είναι αδύνατο να σπάσει από αποφασισμένο άνθρωπο — και δεν είναι αυτός ο στόχος. Ο στόχος είναι να σταματήσουν τα αυτοματοποιημένα, που είναι το 95% του προβλήματος.
SEO και blog μέσα στην εφαρμογή
Το περιεχόμενο δεν πήγε σε ξεχωριστό WordPress. Χτίσαμε content engine μέσα στο Laravel app: επεξεργαστή με υποστήριξη Markdown, αυτόματα meta tags, OG και δομημένα δεδομένα (Article, LocalBusiness, TransportationService), sitemap που ενημερώνεται μόνο του, προτάσεις εσωτερικής διασύνδεσης ανά άρθρο, και κατηγορίες για τουρισμό Αθήνας, business travel και ειδικές περιπτώσεις όπως γάμοι και συνέδρια.
Γράψαμε τα πρώτα οκτώ cornerstone άρθρα ως πρότυπο για την ομάδα του πελάτη — από τον πλήρη οδηγό για τη μεταφορά από το αεροδρόμιο στο κέντρο, μέχρι τη σύγκριση premium transfer με Uber και τα transfers για κρουαζιέρα — και τα δύο πρώτα δούλεψαν αμέσως: top 3 για «private transfer Athens». Όλα σε ελληνικά και αγγλικά, με i18n routing.
Stack και υποδομή
Laravel 11 σε PHP 8.3 με MySQL 8, με Redis για συνεδρίες και την κατάσταση των κρατήσεων. Cloudflare μπροστά για CDN, WAF και επιθετικό caching, Brevo για τα transactional email, Twilio για τα SMS και το pool των αριθμών, Stripe για τις πληρωμές. Στην παρακολούθηση, Sentry για τα σφάλματα και UptimeRobot για τη διαθεσιμότητα. Στα analytics τρέχουν GA4 και μια cookieless πλατφόρμα παράλληλα, ώστε να υπάρχει σημείο αναφοράς για όσα χάνει το ένα.
Αποτελέσματα
Τέσσερις εβδομάδες μετά την έναρξη της ανάπτυξης, το site ήταν live. Το conversion στις κρατήσεις είναι 11,4%, όταν ο διάμεσος της κατηγορίας κινείται στο 4 με 7%. Έρχονται πάνω από 350 τηλεφωνικές κλήσεις τον μήνα, όλες με γνωστή πηγή. Οι απόπειρες scraping που κόβονται ξεπερνούν τις 12.000 τον μήνα, και σταματούν πριν φτάσουν στο pricing API. Το PageSpeed σε κινητό είναι 94, που για custom εφαρμογή με δυναμική τιμολόγηση δεν είναι δεδομένο. Οργανικά, top 3 για «private transfer Athens» και top 5 για «luxury taxi Athens». Και το νούμερο που δείχνει ότι το brand δούλεψε: 31% retention στο πρώτο εξάμηνο — πελάτες που ξαναμπαίνουν να κλείσουν αντί να ψάξουν από την αρχή.
Τι κρατήσαμε από αυτό το έργο
Το custom κερδίζει το template όταν η επιχειρησιακή λογική έχει ιδιαιτερότητες. Η απόδοση τηλεφωνικών κλήσεων ανά πηγή δεν υλοποιείται με plugin, και ήταν από την αρχή η πιο κρίσιμη απαίτηση. Για ανάλογες περιπτώσεις, δείτε το custom web development.
Το naming προηγείται του σχεδιασμού. Αν το «luxi» δεν είχε κλειδώσει πρώτο, το λογότυπο θα είχε διπλάσιες αναθεωρήσεις — γιατί κάθε σχεδιαστική απόφαση απαντά σε ένα όνομα.
Και τα μέτρα κατά των aggregators αξίζουν τον χρόνο τους, όχι για τεχνικούς λόγους αλλά για εμπορικούς: ο πελάτης πλέον έρχεται από το brand και όχι από πίνακα σύγκρισης, όπου η μόνη διαφορά που φαίνεται είναι η τιμή.
Δείτε το έργο: luxi.gr, premium private transfer στην Αθήνα, από αεροδρόμιο και πόρτα σε πόρτα.
Σχετικά:
- Brand identity, η ολοκληρωμένη υπηρεσία brand.
- Δημιουργία λογοτύπου, λογότυπο και brand guidelines.
- Custom Web Development, custom εφαρμογές σε Laravel, Next και Astro.
- Κατασκευή ιστοσελίδων, όλες οι υπηρεσίες web.