Sareerental
← Back home

How this platform works

A quick tour of every feature on Sareerental, what it does for you, and - for the curious - the actual technology behind it.

Passwordless sign-in (magic link + email code)

There are no passwords on this platform. Enter your email on the login page and choose either a one-time 5-digit code or a one-click sign-in link, both sent to your inbox. The first successful sign-in for a new email address creates your account automatically - registration and login are the same flow.

Built with: Emails are sent via the Resend API. A short-lived signed access token (JSON Web Token, 15-minute lifetime) authorizes each request; a separate long-lived refresh token is stored server-side as a salted hash (never in plain text) and rotated every time it's used, so a stolen refresh token only works once before it's invalidated.

Shipping address required before you can list or book

Before you can create a listing or book someone else's, the platform requires a complete address on file (used both as your shipping-to address when you rent something, and your ship-from address when you list something). You'll be prompted to fill it in on your Account page the first time you try either action.

Built with: Enforced by a request guard on the API (NestJS) that checks every required address field is present before the listing/booking endpoint is allowed to run - not just a frontend form validation that could be bypassed.

Listings with moderation queue

Every listing starts as PENDING and is invisible to the public until an admin approves it. Editing an already-approved listing sends it back to PENDING for re-review, so a listing's live public content is always something an admin has actually seen.

Built with: A status state machine (PENDING / APPROVED / REJECTED) stored per listing in MySQL, enforced by role-based guards on the API so only accounts with the admin role can approve or reject.

Photo and video uploads

Add multiple photos and short videos to a listing. Each one is uploaded individually right after the listing itself is created, with a live preview and an 'Uploading media X of Y…' progress indicator.

Built with: Files are stored directly on the server's disk (not a third-party cloud bucket) via a Docker-mounted media volume, and served straight from nginx for speed - the API only handles the upload and validation, not every subsequent view.

Nearby map search

The listings page shows a map centered on your location (or a default city if you don't share it), with one pin per listing - never one per user, since a single person can have many listings. Distance to each listing is shown in kilometers.

Built with: Listing addresses are geocoded to latitude/longitude via OpenStreetMap's free Nominatim service when a listing is created or edited. The map itself renders with Leaflet and OpenStreetMap tiles (no Google Maps, no API key needed). Distance is calculated with the Haversine formula (great-circle distance between two points on a sphere).

Click a map pin to open that listing

Click any pin on the map to go straight to that listing's page - hovering first shows a quick preview (title, price, distance) without navigating away.

Built with: Client-side routing (Next.js's router) swaps the page instantly without a full browser reload; the hover preview is a Leaflet tooltip.

Availability calendar with pickup/return date picking

Every rentable listing shows a real calendar - green days are available, red days aren't (already booked, or blocked by the owner). Click a green day to set your pickup date, then click another to set your return date; the range you've picked is highlighted in blue, with a running price total (rate × days + any deposit) shown underneath.

Built with: The calendar is a plain React component (no external calendar library) that fetches per-day availability from a dedicated API endpoint, which computes it from two sources: the owner's manually-blocked date ranges, and everyone else's active bookings for that listing. A 2-day minimum gap is automatically enforced around every booking and block platform-wide, for cleaning/transit time between rentals, regardless of what any individual listing's settings say.

Booking review page (renter, owner, and shipping info)

Before you confirm a booking, you see a full review: your info as the renter, the listing owner's info, where the item ships to, and the exact cost breakdown (price per day × number of days, plus any deposit, equals the total) - no surprises after you click Confirm.

Built with: The page fetches your profile and the listing's owner info from the API, computes the price breakdown client-side using the same rate/day-count math the server itself uses when the booking is actually created, then submits the booking as one authenticated request.

Photo/video gallery with a clickable filmstrip

A listing with multiple photos or videos shows one large image up top and a row of small thumbnails below it - click any thumbnail to swap the big display, including playing a video right there with full playback controls.

Built with: A single React component tracks which item is 'selected' and swaps the large display between a plain `<img>` and a native HTML5 `<video>` element depending on the media type - no video player library needed.

Share a listing

Tap Share on a listing page. On a phone, this opens your device's normal share sheet (Messages, WhatsApp, email, etc.). On a desktop browser without that capability, it copies the link to your clipboard instead and confirms with 'Link copied!'.

Built with: Uses the browser's native Web Share API where available, falling back to the Clipboard API everywhere else.

Lister subscriptions & contact unlock

Your first listings are free, always - no card required. Past that free limit, a simple monthly subscription unlocks unlimited listings for your account and shows your phone/email to interested renters on every listing you own. An admin can change the free-listing limit and the monthly fee at any time (including setting the fee to 0, which turns the whole platform free for everyone), and can also switch off selling entirely so the platform is rental-only. However you're subscribed or not, the rental payment itself is always arranged directly between you and the other party - see "Booking records the price" below.

Built with: Stripe Checkout in subscription mode, with the price built inline from an admin-configurable, database-stored value at checkout time rather than a fixed Stripe Price object - an admin changing the fee takes effect on the very next checkout with no Stripe-side change needed. Subscription status is kept in sync via Stripe webhooks (checkout completion, renewal, cancellation), and contact-info visibility on a listing is decided server-side from the owner's live subscription status - never trusted from the client.

Likes and view counts

Every listing tracks how many times it's been viewed, and signed-in users can like a listing (tap the heart) to bookmark interest in it - tap again to unlike.

Built with: View counts increment on the server every time a listing's detail page is loaded. Likes are a real per-user relationship stored in the database (one row per user-and-listing pair), so a user's like state is remembered across visits and devices, not just stored in the browser.

Cart, multi-vendor checkout, and coupons

Add items from different owners to one cart, apply a coupon code, and check out - each cart item becomes its own real booking, with the coupon's discount applied proportionally across every item in the cart. Every item in your cart is on hold the moment it's added, not just at checkout - the exact same dates or stock can't end up in two different people's carts at once.

Built with: Checkout re-uses the exact same booking-creation logic a single direct booking uses, just called once per cart item, so cart and direct bookings can never drift into inconsistent behavior. A rental cart item's hold is enforced by including it directly in the availability-overlap query everyone else's search hits; a sale item's hold increments the same stock-reservation counter a real booking uses. Coupons support either a percentage or a fixed-amount discount, tracked with usage limits and expiry dates.

Booking records the price - it doesn't charge you

A booking (direct or via cart) records the agreed price, deposit, and dates as a real record you can both refer back to, but Sareerental never processes that payment itself - you and the other party settle the rental or sale directly, however you'd normally handle it.

Built with: A Stripe Payment Intent scaffold exists in the codebase for a possible future in-platform payment option, but it's not wired into the live money flow described above and isn't configured with a real Stripe key - booking creation works the same with or without it.

Message the lister, right from the listing

Every listing has its own message thread with its owner - ask about condition, pickup, or anything else before you commit to booking. If you own the listing, each prospective renter who messages you gets their own separate thread, and your Messages inbox shows every conversation across every listing with an unread count.

Built with: Messages are stored per (listing, sender, recipient) - there's no general-purpose inbox unrelated to a listing. Opening a thread marks the other person's messages as read, matching the PRD's read-receipts feature without a separate endpoint.

Shareable links

A listing's URL is a readable slug built from its title, not a random id, so a link you post to social media or a group chat reads like the actual item, not a database key.

Built with: Listing.slug is generated once at creation (slugified title plus a short random suffix for uniqueness) and stored alongside the internal id - lookups accept either, so nothing that already links by id breaks.

Under the hood, platform-wide

The site is a monorepo (pnpm workspaces + Turborepo) split into a Next.js frontend and a NestJS API backed by MySQL through Prisma. Both run in Docker containers behind an nginx reverse proxy, which also serves uploaded media files directly for speed.