Skip to content

Real estate marketplace

Property On Set

A multi-sided real estate marketplace: buyers, renters and investors on one side; agents, deals and an admin CMS on the other.

In DevelopmentFull StackProduct Design

Built and deployable (Next.js on Vercel, API on Render, Supabase). No public deployment is linked yet, and listing data is generated for development.

Period
Aug 2026
Status
In Development
Role
Product design, Frontend
Built with
Next.js 16, React 19

The problem

Why this needed to exist

A property marketplace is several products sharing one database. Buyers, renters and investors want discovery; agents want a listing pipeline and a way to negotiate; administrators need to stop bad listings reaching the public.

Each side has different permissions over the same records, which is exactly where marketplaces leak data.

Who it’s for

  • Buyers and renters
  • Short-let guests
  • Property investors
  • Listing agents
  • Platform administrators

The solution

How it works

Separate surfaces for each role — public discovery for buy, rent, short-let and invest; an agent dashboard with listing drafts and deals; an admin area for properties, users and analytics — all backed by one Express + Prisma API that verifies Supabase sessions on every protected route.

Listings are created as drafts and only become publicly visible once published; the public endpoint serves published listings only.

Three sides, one API

  1. Public
    • Buy
    • Rent
    • Short-let
    • Invest
  2. Agents
    • Listing drafts
    • Deals & installments
    • Dashboard
  3. Admin
    • Properties
    • Users
    • Analytics
  4. API
    • Express + Prisma
    • JWKS token check
  5. Data
    • Supabase Postgres
    • Cloudinary
    • Mapbox
Every protected route verifies the Supabase session and loads the user from the database before checking role.

Implemented

What’s actually built

  • Discovery by intent

    Dedicated buy, rent, short-let and invest routes with working listing filters, property detail pages and map-based location context.

  • Agent listing workflow

    Agents create listing drafts through a guided flow; publishing is controlled, and every change is written to a property history.

  • Deal negotiation

    Agents and clients negotiate deals with payment plans and installments, tracked from both sides.

  • Admin CMS

    Properties, users and analytics, with suspend and delete actions for users and agents.

  • Accounts and onboarding

    Email/password and Google sign-in through Supabase Auth; the API verifies tokens against Supabase’s published JWKS and syncs an application user.

  • Crypto payments

    A crypto payment flow with per-network deposit addresses and payment status tracking, alongside investment charts and discounts.

My role

What I did

Product design and full-stack implementation: the Next.js frontend, the Express/Prisma API, the data model (users, agents, properties, leads, deals, installments, reviews, favourites, crypto payments) and the deployment setup across Vercel, Render and Supabase.

Responsibilities

  • Product design
  • Frontend
  • Backend API
  • Data model
  • Security review

Stack (verified from source)

  • Next.js 16
  • React 19
  • Tailwind CSS 4
  • Framer Motion
  • Express
  • Prisma
  • Supabase (Postgres + Auth)
  • Mapbox
  • Cloudinary
  • Docker

Decisions

Technical and design choices

  1. 01

    Verify tokens locally

    The API verifies Supabase access tokens against the published JWKS — no shared secret on the server — and keys application users on the auth uid.

  2. 02

    Published-only public API

    The public listings endpoint can only return published properties; drafts live behind agent routes.

  3. 03

    Free-tier friendly topology

    Frontend on Vercel, API in Docker on Render with a health check, Postgres through Supabase’s pooler — documented as a Render blueprint.

Trade-offs

Challenges along the way

  1. 01

    A security pass before launch

    A dedicated review fixed data over-exposure in API responses, removed an unauthenticated endpoint, hardened uploads, and closed a stored XSS in JSON-LD script tags.

  2. 02

    Configuration that wiped itself

    The Cloudinary configuration was silently reset on every boot; tracking that down was a lesson in initialisation order.

Lessons

What I took away

  • In a multi-sided marketplace, most of the design work is deciding who can see which version of a record.

What’s next

Planned — not built

Planned work

  • A public production deployment with real, agent-submitted listings
  • Replacing generated development listings and placeholder testimonials before launch

Current limits, stated plainly

  • Listing data in development is generated (a bulk generator creates sale and rent listings across US markets); it is not real inventory.