Baytup
A two-sided rental marketplace built for the Algerian market — unifying short-term stays and vehicle rentals into a single trilingual (EN/FR/AR), dual-currency (DZD/EUR) platform with real-time messaging, local payment rails, and identity-verified hosts.
Airbnb + Turo, localized for Algeria.
Baytup is a production-grade SaaS marketplace that lets Algerian hosts list properties (apartments, houses, villas, studios, rooms, riads, guesthouses, hotel rooms) and vehicles (cars, motorcycles, vans, SUVs, trucks, buses, bicycles, scooters, boats) while guests discover, book, pay for, and review them — all with trilingual UX and dual-currency pricing.
One platform, two asset classes, three languages, two currencies, and payment rails built for the local market.
A fragmented rental ecosystem with no trust layer.
- Property rentals scattered across classifieds and social groups with no trust layer.
- Vehicle rentals dominated by offline agencies with no digital booking.
- International platforms (Airbnb, Booking) have thin Algerian inventory and don't support local payment methods or full Arabic/French localization.
One trust-driven marketplace — localized end-to-end.
Baytup consolidates both rental categories into a single marketplace with local payment support (RIB, CCP, BaridiMob via SlickPay), native Arabic RTL UI, identity-verified hosts, and a role-based admin console. Real-time messaging and a 40-type notification engine keep guests and hosts coordinated end-to-end.
Three roles, one platform.
Guest
Travelers and renters browsing stays or vehicles, booking and paying securely, saving favorites, messaging hosts, and leaving reviews.
Host
Property and vehicle owners who apply for verification, list assets, manage availability and pricing, approve bookings, respond to reviews, and withdraw earnings.
Admin
Platform operators who moderate listings, review host applications, manage users, handle disputes, and process payouts.
What the platform does.
Discovery & booking
- Hero homepage with category split (Stays / Vehicles) and featured listings.
- Advanced search with interactive map and marker clustering.
- Rich filters — location, date range, price, guest count, type, amenities/features, instant-book, ratings.
- Listing detail pages with photo carousel, embedded map, amenities, host profile, reviews, inline booking widget.
- Date-range calendar with live pricing breakdown (nightly × stay + cleaning + service fee + taxes + deposit).
- Wishlist / saved listings per guest.
Host tooling
- Multi-step onboarding — ID front/back, proof of address, profile photo, property intent, terms.
- Listing wizard supporting both stays and vehicles with category-specific fields.
- Pricing engine — base price, cleaning fee, service fee, security deposit, per night/day/week/month/hour cadence.
- Availability management with blocked dates and min/max stay.
- Earnings dashboard with charts, revenue analytics, booking history.
- Payout requests with local rails — RIB, IBAN, CCP, BaridiMob.
Admin console
- User management — activate / deactivate / delete / role changes.
- Listing moderation — approve / reject / feature.
- Host application review with accept / reject and feedback.
- Booking oversight, cancellation management, dispute handling.
- Platform-wide analytics.
Real-time layer
- Socket.IO-powered in-app messaging between guests and hosts.
- Conversations scoped to a listing or booking with participant read receipts.
- Typed messages — text / image / file / system.
- Live notification system covering 40+ event types across booking lifecycle, payments, reviews, payouts, moderation, and account events.
- Notification center with unread badge, filters, bulk mark-as-read, TTL auto-cleanup.
Localization & accessibility
- Three languages — English, French, Arabic with full RTL layout switching.
- Two currencies — DZD and EUR with live conversion throughout the UI.
- Per-user language + currency preferences persisted across sessions.
- Custom typography per language (Noto Sans Arabic for ar, Inter for en/fr).
Trust & safety
- Email verification with tokenized links.
- Password reset flow.
- Google OAuth social login alongside email/password.
- Host identity verification with ID documents and address proof.
- Review system — overall rating + 6 subcategories (cleanliness, communication, check-in, accuracy, location, value) with host responses.
- Superhost badge for consistently high-rated hosts.
- Rate limiting, Helmet security headers, input validation, sanitization.
Payments
- Integrated SlickPay — Algerian payment gateway — for card payments.
- Webhook-based payment confirmation.
- Automated booking status transitions via scheduled cron jobs.
- Secure payout workflow with admin approval.
How it holds together.
Monorepo-like split
Two independently deployable projects — a Next.js client and an Express server — communicating over REST and WebSocket. Clean separation lets each deploy and scale on its own cadence.
Role-based routing
One /dashboard URL renders one of three experiences (Admin / Host / Guest) based on the authenticated user's role. Server-side middleware (protect, authorize(role), hostOrAdmin, ownerOrAdmin) enforces the same authorization.
Polymorphic listing model
A single Listing schema handles both stays and vehicles via a discriminator category field plus sub-documents (stayDetails / vehicleDetails). Search, booking, reviews, and wishlists stay uniform across both asset types while each category keeps its own rich fields and filters.
GeoJSON + geo-indexing
Listings store { type: 'Point', coordinates: [lng, lat] } with a 2dsphere index, enabling fast radius and bounding-box search for the interactive map UI with marker clustering.
Notification engine
A generalized Notification model with 40+ enumerated types and severity levels. Every domain event emits both an in-app notification (delivered live via Socket.IO) and, for important events, an email. A TTL index auto-prunes old entries.
Conversation model
Conversations are first-class, optionally scoped to a listing or booking, with participant read-receipts (lastReadAt) and typed messages — text, image, file, or system.
Dual-currency UX
Prices are stored in a single canonical currency per listing but rendered in the user's preferred currency throughout the app, with the preference persisted.
RTL-first design system
Tailwind config and components tested in both LTR and RTL. The root <html dir> attribute flips on language change so layout mirroring works across every page, and Arabic gets its own font stack.
Modern, proven, boring-where-it-matters.
Frontend
- Next.js 14 (App Router, SSR)
- React 18 + TypeScript
- Tailwind CSS (custom palette, RTL variants)
- Zustand + React Context
- Axios with JWT interceptors
- Socket.IO client
- React Hook Form + Zod
- Radix UI primitives
- Recharts + Chart.js
- Google Maps JS API (@react-google-maps/api)
- Google OAuth (@react-oauth/google)
- Embla Carousel, React Hot Toast, Lucide
Backend
- Node.js + Express 4
- MongoDB + Mongoose (mongoose-paginate-v2)
- Socket.IO (bidirectional realtime)
- JWT + bcryptjs
- Google Auth Library (OAuth token verification)
- Multer + Sharp (uploads + image processing)
- Nodemailer (transactional email)
- Helmet, CORS, express-rate-limit, express-validator
- Winston + Morgan
- node-cron (scheduled jobs)
- Compression (gzip)
Infrastructure
- Ubuntu 24.04 VPS
- Nginx reverse proxy
- Let's Encrypt / Certbot SSL
- PM2 process manager (client + server)
- CDN-ready static assets + served uploads
The hard parts — and how they got solved.
Dual-asset search
One schema, two very different filter surfaces. Solved with a category-aware query builder and a dynamic filter-data endpoint that returns the right facet set per category.
Real-time at scale
Socket.IO rooms keyed by userId let the server push notifications without broadcast overhead. Each domain event persists a Notification document and emits to connected recipients.
RTL + trilingual i18n
User-facing copy lives in JSON locale bundles (one per page). Arabic needs RTL layout plus a dedicated font stack — handled with Tailwind's rtl: variant and a language-scoped font.
Local payment rails
Algerian banking uses a 20-digit RIB, plus CCP and BaridiMob. The Payout model supports all of them with appropriate validation.
Role-based dashboards at one URL
A single /dashboard URL renders three entirely different UIs — resolved at render time from the authenticated user's role with matching server-side guards.
Booking state machine
pending → confirmed → completed (or cancelled / dispute), with payment status decoupled (pending / completed / failed / refunded). A cron job auto-transitions bookings once payment confirms.
Nine core entities.
Schemas
- UserIdentity, role, profile, preferences, host profile, stats.
- ListingStay or vehicle with pricing, availability, images, geo.
- BookingListing × guest × host, dates, pricing breakdown, payment, status.
- ReviewBidirectional with 6 subcategory ratings and host responses.
- Conversation + MessageListing/booking-scoped chat with read receipts.
- NotificationTyped, prioritized, TTL-expiring in-app events.
- HostApplicationIdentity docs, host intent, admin review workflow.
- PayoutLocal bank details, status, admin processing.
- WishlistUser ↔ listing saves.
Shipped to production.
- Production deployment on a Linux VPS with Nginx + Let's Encrypt + PM2 supervision.
- Automated transactional email pipeline — account verification, password resets, booking confirmations, notifications.
- Structured logging + rate limiting for observability and abuse prevention.
- Seed scripts for reproducible dev environments.
Let's talk about your platform.
If Baytup looks close to what you're building — two-sided marketplace, real-time messaging, local payments, multi-language — we'd like to hear about it.