Skip to content
All projects

Private BetaMobility marketplace1-minute read

Khodni Maak

A commute marketplace for Jordan built around the route, not the listing.

Built with
  • Flutter (PWA)
  • NestJS
  • TypeScript
  • PostgreSQL
  • PostGIS
Khodni Maak: the Arabic landing page with its two paths beside the one-screen payment to the captain, shown with seeded demo data

Problem

Shared commuting happens in social-media groups: offers get lost, phone numbers are public and free seats are unclear.

Solution

A captain already driving from A to B publishes the ride and sets a seat price; passengers whose route and time genuinely fit book a seat and pay that price to the captain directly. It is deliberately not a taxi app: no on-demand dispatch and no commission.

My contribution

Product, UX, engineering and deployment.

Key features

  • Scheduled and recurring carpooling
  • Route matching with controlled detours
  • Direct CliQ seat payments, confirmed by the captain
  • Arabic and English

Outcome

Free for passengers, who pay the captain the displayed seat price directly by CliQ.

Private beta, invite-only. There has been no public launch, so there are no usage figures.

Technical details and full write-upArchitecture, security, testing and decisions, for readers who want the detail.

Overview

Khodni Maak is a scheduled carpooling platform for Jordan. A captain who is already driving from A to B publishes the ride and sets a seat price; passengers whose route and time genuinely fit book a seat and pay that price to the captain directly. It is deliberately not a taxi app: there is no on-demand dispatch, and the platform takes no commission.

Private beta: the platform is deployed at khodnimaak.3dot.tech, and access is by a one-time code from the team, requested through a form on the site or in the app. There has been no public launch, and its operating model is pending Jordanian legal review.

Areas
  • Scheduled carpooling
  • Route matching
  • Recurring commutes
  • CliQ payments
  • Captain subscription
  • Arabic and English

The problem

Shared commuting between Jordanian cities already happens, mostly in WhatsApp and Facebook groups. The groups work as a notice board and fail as a system: offers scroll away, phone numbers are public, nobody knows how many seats are really left, and a driver who agrees to “pick people up” can end up crossing a whole city. There is no calendar for a trip that repeats five days a week, no waiting list, and no record when someone does not show up.

Market context

A review of regional products found several small intercity ride listings and no clear leader. None described weekly recurring commutes in depth, none used a flat driver subscription, and waitlists, calendars and share links were absent from the local listings reviewed. International references (BlaBlaCar, Poparide and commuter products) supplied useful patterns: request-or-instant booking, published cancellation rules, and phone numbers revealed only after a booking.

Business model

Using Khodni Maak is free for passengers. You only pay the captain the displayed seat price.

There are three parties and exactly two payments. They have different screens, words and colours, and are never mixed.

  • Passenger to captain: the seat price the captain set for that ride, paid directly by CliQ and confirmed by the captain.
  • Captain to platform: a flat subscription, 10 JOD per month by default, which an admin verifies before it entitles the captain to anything.
  • Passenger to platform: nothing. There is no booking fee and no commission, and the platform never receives or holds passenger money.

What changed since the first version

The first version of this page described an earlier build. Since then the payment model was corrected in the product’s wording and enforced in its code, all three surfaces were rebuilt, and the way in and the main journeys were shortened.

  • Sign-in: a phone number and a password. A one-time access code from the team is used once, for the first activation or a forgotten password, and always ends in a password. People ask for access through a “Request access” form on the site or in the app, and help is a form too, in the app or on the site.
  • App: a shared design system; search where a city, an area or a governorate means anywhere inside it, with results that explain the fit in plain language; payment to the captain on one compact screen; a captain “Today” screen; publishing in three screens; verification-first onboarding; commute circles for regular seats on a recurring ride; in-app policy pages; and place search that forgives Arabic and English spelling.
  • Landing page: about six phone screens, with two paths at its centre, “Find a ride” and “I’m a captain”, a “Who pays whom” section and one install guide.
  • Owner console: a nine-entry menu, one work queue that also lists what blocks a launch, queues for access and help requests, a notification centre, team management without server access, a review card for captain verification, and the subscription payment review.
  • Security: repeated independent reviews, the latest covering the new sign-in, the public request forms and the payment-dispute states; the findings were fixed and covered by regression tests.
  • Tests: automated API tests that include an end-to-end business scenario, app widget and unit tests, static checks for the owner console, and a 32-step production smoke test.

The passenger experience

Three questions on one screen: from where, where to, when. Places are found by typing in Arabic or English, with forgiving spelling, and a city, an area or a governorate means anywhere inside it. Each result shows the pickup time, the labelled seat price, the seats left, the captain and one plain-language line on why the ride fits, never a score. From there the journey is the ride page, then booking and payment, then the passenger’s trips. A full ride offers a waitlist, a ride cancelled by the captain shows a replacement, and a regular commute is saved once and searched in one tap.

The captain experience

Onboarding is verification first and never asks for money before the captain is verified; the subscription comes after. The “Today” screen opens with one “waiting for you” strip, then the next ride. Publishing is three screens: where, when, then the seats and the seat price above a review card; everything else is under “More options”. Recurring rides appear in a day, week, month and agenda calendar; a single day can be skipped, a recurring ride paused, a holiday blocked. The passenger list shows who is coming, where they board, and each passenger’s payment state in words. A trip cannot be finished while a submitted payment is unanswered, and cancelling a ride with paid passengers shows them first and opens the refunds the captain owes.

Smart route matching

Matching is geometric, deterministic and explainable. PostGIS measures how far the passenger’s pickup and drop-off are from the captain’s route and where along the route they fall; a scoring function then weighs route fit, time difference, the detour required and the captain’s reliability. A trip in the opposite direction never matches, even if both points lie on the route. The passenger is never shown a number: each result says in plain language why the ride fits, and the server recomputes the match at booking time.

Controlled detour

Each captain sets a maximum detour in minutes. Every accepted passenger who is off the route consumes part of that budget, so several small detours cannot add up to a large one. The captain always sees the original trip time and the time with passengers.

Pickup hubs

Universities, bus terminals and major junctions are first-class records managed by the admin. A captain can limit pickups to hubs; when several passengers are near the same hub, the manifest suggests meeting there and estimates the minutes saved.

Calendar and recurring commutes

A recurring series is stored as a template and materialised as individual rides inside a rolling booking horizon, one per date, so the system never generates unbounded records. Passengers can ask for a seat on every instance of a series; the captain approves once.

CliQ payments

Money never passes through the platform. The order is fixed: the passenger requests a seat or books instantly; the captain accepts; the passenger transfers the seat price in their own banking app and enters the transfer reference; the captain confirms receipt; only then is the seat confirmed and the boarding PIN shown. “Sent” is never shown as “confirmed”. Paying is one compact screen: copy the captain’s alias, enter the transaction number, then wait for the captain. Both sides are reminded, the seat stays held while a payment is under review, and when the two sides disagree the case goes to the team. One reference can back one payment across the whole platform. No CliQ API is used or claimed.

Entitlement: one rule

One server-side rule decides whether a captain may take new business: a verified captain with an admin-verified subscription that is inside its paid period. Every path that creates new business checks it: publishing, recurring generation, new bookings, accepting requests and appearing in search. It is evaluated from dates at request time, so there is no grace period. Trips that are already confirmed stay manageable: the passenger list, chat, boarding, completion, cancellation and refunds keep working.

Subscription payment review

The captain’s subscription is the only payment the platform itself receives, so the owner reviews each one. A queue lists what is waiting; each payment has its own review page with the expected amount, the stated amount, the transfer reference and the receipt. A calm “needs review” hint appears when a receipt was used before or the amounts differ: a hint, not a verdict. The reviewer can ask the captain a question and receive one reply, then accept or reject, with an audit entry. A submitted payment entitles nothing; only a verified one does. The owner’s money report counts verified subscription payments only; seat-price payments between passengers and captains are listed apart and never counted as the platform’s.

Safety

A captain’s identity, vehicle and documents are reviewed before they can publish. Boarding is confirmed with a four-digit PIN, or with a QR code opened for that one passenger. Passengers can share a trip through an expiring, revocable link. Ratings are limited to completed trips, reports and disputes go to a staff queue with a combined timeline, and one accusation cannot wreck a reliability score.

Privacy

Phone numbers, CliQ details and the plate are shown only between the two parties of an accepted booking. Search results show areas, not addresses. Demand data shown to captains is aggregated by city. Identity documents and payment receipts are private files served only to their owner and to authorised staff.

Selected interface

The public landing page and its “Who pays whom” section, then six app screens captured from a local build with seeded demo data: demo names, CliQ aliases and transfer references. No real user appears in them.

Technical architecture

  • App: Flutter, shipped as an installable PWA (Arabic RTL by default, English LTR), with one codebase prepared for Android and iOS later.
  • API: NestJS and TypeScript, raw SQL, a single state machine for bookings and a single entitlement rule for captains.
  • Database: PostgreSQL with PostGIS: route geometries, spatial indexes, row-level locks for seats.
  • Maps and routing: providers behind interfaces; OpenStreetMap tiles for display, a routing engine pluggable when available.
  • Landing site: static HTML in Arabic and English, with no build step.
  • Owner console: a dependency-free web app for captain verification, subscription payments, disputes, geography and analytics.
Stack
  • Flutter (PWA)
  • NestJS
  • TypeScript
  • PostgreSQL
  • PostGIS
  • Nginx
  • systemd

Application security

Opaque server-side sessions in HttpOnly cookies, CSRF protection, role checks on the server for every resource, strict upload validation with re-encoding, private file storage, rate limits, a strict Content Security Policy, and an audit log for every privileged action. There is no default password and no universal sign-in code.

Deployment

One Linux server shared with other projects, with isolated paths, a dedicated system user and database, a hardened systemd service, Nginx with HTTPS, daily backups with a tested restore, and atomic releases that can be rolled back by switching a symlink.

UX and design process

The interface answers one question per screen, on one design system shared by the app, the landing page and the owner console. Advanced options are folded away. Arabic copy uses everyday Jordanian phrasing, and one glossary fixes the words: it is always the seat price, and “sent” is never “confirmed”. Motion is used for feedback and respects reduced-motion settings. The palette avoids taxi yellow in favour of teal, ink and sand.

Challenges and solutions

  • The last seat. Ten people can press Book at once. Every booking locks the ride row, so exactly one gets the seat; an automated test fires ten simultaneous requests to prove it.
  • Trust without holding money. A state machine tracks who claimed to pay and who confirmed, with unique references, holds that expire, and a manual refund workflow.
  • Two payments that must never be confused. The seat price and the subscription have different screens, words and colours, one glossary, and automated checks on the wording.
  • Recurring rides without infinite data. Templates plus a rolling horizon, with idempotent generation.
  • Privacy in a marketplace. The same booking is serialised differently for the passenger, the captain and staff, and by state.
  • A PWA that updates safely. A versioned service worker replaces the cache as a whole and asks the user to reload.

Outcome

The platform is deployed and verified end to end on the production server. Automated API tests, app tests and a 32-step production smoke test cover access requests and sign-in, captain verification, the subscription and its review, publishing, matching, booking, payment to the captain, waitlist, cancellation, replacement rides and refunds. It is in private beta, with access by a code from the team: there has been no public launch, so there are no usage figures to report.

The link below opens the public landing page only. The app is in private beta, and access is by a code from the team.

Lessons

Carpooling is a matching problem before it is a listing problem; the route has to be a first-class object. Saying in plain words why a ride fits builds more trust than a score. A marketplace that does not touch the money still has to model it carefully, and who pays whom has to fit in one sentence that the wording, the code and the reports all agree on.

Roadmap

Access codes sent by SMS, a self-hosted routing engine for exact road distances, push notifications, native Android and iOS builds, employer and university commute groups, and integrated payments once a provider is available.