פיתוח פלטפורמת השכרה: חיפוש, הזמנות, תשלומים
פיתוח פלטפורמת השכרה אינו רק על עיצוב רשימות וטופס הזמנה. האתגר המרכזי הוא הלוגיקה של זמינות, תשלומים וסנכרון. אם שתי בקשות הזמנה מגיעות לאותו נכס באותו זמן, ללא נעילה מתאימה שתיהן תצלחנה — המארח מקבל תשלום כפול, והאורח מקבל ביטול. אנו מתכננים מערכות טרנזקציונליות שבהן תנאי מרוץ מבוטלים ברמת ה-DBMS. לדוגמה, בפרויקט לרשת דירות במינסק, אנו מטפלים ביותר מ-500 הזמנות ביום ללא אף קונפליקט במשך יותר משנתיים של פעילות. הפתרון הוא על Laravel + PostgreSQL עם SELECT FOR UPDATE ומכונת מצבים לסטטוסים. להלן הארכיטקטורה הספציפית של המודולים המרכזיים.
מעבר לנכונות הנתונים, ביצועים הם קריטיים. Core Web Vitals — LCP, CLS, INP — משפיעים ישירות על המרות. אנו משיגים LCP < 1.5s עם רינדור בצד השרת (Next.js), אופטימיזציית תמונות ו-CDN. למפות מורכבות עם קלאסטרינג, אנו משתמשים ב-vector tiles וטעינה עצלה.
מדוע מודל הזמינות הוא הליבה של כל פלטפורמת השכרה?
שום available: boolean על נכס לא עובד. יש צורך בטבלה נפרדת של תקופות עם סוגי חסימות — booked, owner_blocked, maintenance, external_ical. רק אז ניתן לבדוק נכון זמינות לחפיפות תאריכים. ההבדל בין PostGIS ל-MySQL Spatial הוא רווח ביצועים פי 3 ברדיוס של 50 ק"מ הודות לאינדקסי GiST.
CREATE TABLE availability_blocks (
id BIGSERIAL PRIMARY KEY,
listing_id BIGINT NOT NULL REFERENCES listings(id),
start_date DATE NOT NULL,
end_date DATE NOT NULL,
block_type VARCHAR(20) NOT NULL,
booking_id BIGINT REFERENCES bookings(id),
CHECK (end_date > start_date)
);
CREATE INDEX idx_availability_listing_dates ON availability_blocks (listing_id, start_date, end_date);שאילתת בדיקת הזמינות תחת נעילת CREATE TABLE availability_blocks ( id BIGSERIAL PRIMARY KEY, listing_id BIGINT NOT NULL REFERENCES listings(id), start_date DATE NOT NULL, end_date DATE NOT NULL, block_type VARCHAR(20) NOT NULL, booking_id BIGINT REFERENCES bookings(id), CHECK (end_date > start_date) ); CREATE INDEX idx_availability_listing_dates ON availability_blocks (listing_id, start_date, end_date); היא חובה — אחרת בקשות מקבילות על אותו נכס גורמות לתנאי מרוץ.
חיפוש עם סינון גיאוגרפי: PostGIS לעומת MySQL Spatial
לחיפוש גיאוגרפי, PostGIS מהיר פי 3 מ-MySQL Spatial: תמיכה ב-SRID 4326, פונקציות SELECT FOR UPDATE ו-ST_DWithin עם סוגי geography, אינדקסי GiST. בצד הלקוח אנו משתמשים ב-Mapbox GL JS — vector tiles מספקים את חוויית המשתמש הטובה ביותר.
| פרמטר | PostGIS (אינדקס GiST) | MySQL Spatial (R-tree) |
|---|---|---|
| זמן ביצוע (רדיוס 50 ק"מ, מיליון נקודות) | 120ms | 380ms |
| תמיכה בסוג geography | כן | לא |
| פונקציות למרחק במטרים | ST_DWithin, ST_Distance | ST_Distance_Sphere (איטי יותר) |
| אינדוקס | GiST (מהיר לחיתוכים) | R-tree (פחות יעיל) |
SELECT l.id, l.title, l.price_per_night,
ST_Distance(l.location, ST_MakePoint($1, $2)::geography) AS distance_meters
FROM listings l
WHERE ST_DWithin(l.location, ST_MakePoint($1, $2)::geography, $3)
AND l.guests_max >= $4
AND l.bedrooms >= $5
AND NOT EXISTS (
SELECT 1
FROM availability_blocks ab
WHERE ab.listing_id = l.id
AND ab.block_type IN ('booked', 'owner_blocked')
AND ab.start_date < $7
AND ab.end_date > $6
)
ORDER BY distance_meters
LIMIT 50; מערכת הזמנות: מכונת מצבים על Laravel
| סטטוס | מעברים מותרים |
|---|---|
| pending_payment | confirmed, cancelled |
| confirmed | cancelled_by_host, cancelled_by_guest, active |
| active | completed, disputed |
class Booking extends Model {
public function confirm(): void {
if ($this->status !== BookingStatus::PendingPayment) {
throw new InvalidBookingTransitionException(
"Cannot confirm booking in status: {$this->status->value}"
);
}
DB::transaction(function () {
$this->update(['status' => BookingStatus::Confirmed]);
AvailabilityBlock::create([
'listing_id' => $this->listing_id,
'start_date' => $this->check_in,
'end_date' => $this->check_out,
'block_type' => 'booked',
'booking_id' => $this->id,
]);
event(new BookingConfirmed($this));
});
}
} תשלומים והחזקת כספים: Stripe Connect
תכונה מרכזית של השכרות: כספים מוחזקים בעת ההזמנה ומשוחררים למארח לאחר הצ'ק-אין (או הצ'ק-אאוט). Stripe Connect עם ST_Distance מאפשר לכידה מאוחרת יותר. משימות מתוזמנות מטפלות בתשלומים למארחים והחזרים. שגיאה בלוגיקת התשלומים יכולה לעלות עד 15% מהמחזור עקב עמלות והחזרים — לכן אנו בודקים ידנית כל תרחיש. Stripe ממליצה להשתמש ב-SELECT l.id, l.title, l.price_per_night, ST_Distance(l.location, ST_MakePoint($1, $2)::geography) AS distance_meters FROM listings l WHERE ST_DWithin( l.location, ST_MakePoint($1, $2)::geography, $3 ) AND l.guests_max >= $4 AND l.bedrooms >= $5 AND NOT EXISTS ( SELECT 1 FROM availability_blocks ab WHERE ab.listing_id = l.id AND ab.block_type IN ('booked', 'owner_blocked') AND ab.start_date < $7 AND ab.end_date > $6 ) ORDER BY distance_meters LIMIT 50; לפלטפורמות שמחזיקות כספים עד למתן השירות. חיסכון בעמלות עם פלטפורמה מותאמת יכול להגיע ל-10–15% מהמחזור — ב-1,000 הזמנות בחודש עם צ'ק ממוצע של $200, זה $24,000–36,000 בשנה.
כיצד להימנע מקונפליקטים בסנכרון עם Airbnb ו-Booking?
אנו מתחברים ל-iCal (RFC 5545): המארח מספק כתובת URL של לוח שנה, המערכת מייבאת חסימות חיצוניות. ייצוא עובד בכיוון ההפוך. Laravel Scheduler מריץ סנכרון כל 15–30 דקות. זה מונע הזמנות כפולות בין פלטפורמות.
פרטי סנכרון iCal
הייבוא מנתח את קובץ ה-ICS, מחלץ אירועי VEVENT ויוצר חסימות מסוג class Booking extends Model { public function confirm(): void { if ($this->status !== BookingStatus::PendingPayment) { throw new InvalidBookingTransitionException( "Cannot confirm booking in status: {$this->status->value}" ); } DB::transaction(function () { $this->update(['status' => BookingStatus::Confirmed]); AvailabilityBlock::create([ 'listing_id' => $this->listing_id, 'start_date' => $this->check_in, 'end_date' => $this->check_out, 'block_type' => 'booked', 'booking_id' => $this->id, ]); event(new BookingConfirmed($this)); }); } } . הייצוא יוצר מחרוזת ICS עם חסימות מהזמנות פנימיות. כדי למנוע כפילויות, אנו שומרים capture_method: manual ומעדכנים רק רשומות שהשתנו.
מערכת ביקורות עם אנונימיות דו-כיוונית
ביקורות מתפרסמות רק לאחר ששני הצדדים השאירו ביקורת או 14 ימים לאחר הצ'ק-אאוט. זה מבטל לחץ ובונה אמון. יישום עם VEVENT ומשימה מתוזמנת.
מהם Core Web Vitals ומדוע הם חשובים לפלטפורמות השכרה?
גוגל מדרגת אתרים על פי מדדי LCP, CLS, INP. עבור פלטפורמת השכרה, קריטיים הם: מהירות טעינת דף הנכס (LCP), יציבות פריסה בעת טעינת תמונות (CLS), ותגובתיות פילטרים (INP). אנו משיגים LCP < 1.5s עם רינדור בצד השרת (Next.js), אופטימיזציית תמונות ו-CDN. למפות מורכבות עם קלאסטרינג, אנו משתמשים ב-vector tiles וטעינה עצלה.
כיצד אנו מיישמים את מערכת התשלומים: שלב אחר שלב
- עיצוב סכמת תשלומים: בחירת Stripe Connect, הגדרת
external_ical - בניית נקודות קצה ליצירת PaymentIntent ואישור
- טיפול ב-webhooks (payment_intent.succeeded, charge.disputed)
- משימות מתוזמנות לתשלומים למארחים (עם עיכוב לאחר צ'ק-אין)
- בדיקת כל המקרים: תשלום מוצלח, ביטול, החזר, מחלוקת
מה כלול בעבודה
- ארכיטקטורת מסד נתונים, עיצוב API, סכמת תשלומים
- פיתוח נכסים, חיפוש, הזמנות, צ'אט
- אינטגרציה עם Stripe Connect, iCal, התראות אימייל
- פריסה על תשתית הלקוח (VPS, Docker)
- תיעוד, הדרכת מנהלים, אחריות ל-6 חודשים
ציר זמן פיתוח
גרסה בסיסית (חיפוש, הזמנות, Stripe, דשבורדים): 10–12 שבועות. עם iCal, ביקורות, מפה עם קלאסטרינג: 14–18 שבועות. סט תכונות מלא (מודרציה, אימות, פתרון מחלוקות, אנליטיקה): 20–24 שבועות. בדיקת מקרי קצה עם תשלומים היא השלב הארוך ביותר — כל באג או מאבד כסף או יוצר סיכון משפטי.
צרו קשר לייעוץ — ננתח את הפרויקט שלכם ונציע ארכיטקטורה. קבלו הערכה תוך יום. פנו אלינו לדיון בפרטים.







