AGdev
AGdev

Property Decision Support

Property advisory · Service platform

From choosing a service to a prepared property visit.to a prepared property visit.

I designed and built Property Decision Support for an independent property advisor working with buyers and sellers in Malta and Gozo.

View live site
Property Decision Support service platform showing service selection and booking preparation
Role
Full-Stack Product Engineer
Ownership
End-to-end service platform
Status
Production
Core flow
Choose → Pay → Book → Prepare
Project snapshotThe challenge01 Buyer and seller journeys02 Payment and booking03 Content and private data04 Appointment preparationProduction realityHow it connectsThe outcomeWhat I ownedBuilt with

[ Project snapshot ]

Problem

Property advice depends on context. Buyers and sellers need different support, while the advisor needs useful information before the appointment instead of collecting it during the visit.

[ Let’s work together ]

Building a service where the important work starts before the appointment?starts before the appointment?

I can help turn the journey behind the service into a product that works end to end.

AGdev
ImprintPrivacy policy
ImprintPrivacy policy

© 2026 Aleksandar Gjurchevski. All Rights Reserved.

© 2026 Aleksandar Gjurchevski. All Rights Reserved.

What I built

A commercial service platform with separate buyer and seller journeys, online payment, protected booking access, live availability, structured intake, private document uploads, and transactional communication.

My responsibility

Product flows and UX/UI, frontend and backend, booking architecture, payments, private data, access security, scheduling, forms, CMS architecture, integrations, SEO, infrastructure, and production.

[ The challenge ]

The website had to sell the service without oversimplifying it.

Property Decision Support is deliberately not an estate agency, brokerage service, formal valuation, or building survey. The advisor works independently for one side of the property decision.

A buyer may need help understanding what is unclear before making an offer. A seller may need to understand what should be prepared before listing or why an existing sale is losing momentum.

The website therefore had to explain the service clearly, help people choose the right kind of support, collect payment, and carry enough context into the actual appointment. I built the booking around that whole journey instead of treating the website, checkout, calendar, and intake form as separate parts.

The booking connects what the client buys with what the advisor needs to deliver.
01

[ Buyer and seller are not the same flow ]

They use the same platform, but they are trying to make different decisions.

The obvious option would have been one generic property form with a few fields shown or hidden depending on the selected service. I decided against that.

A buyer needs to explain the property they are considering, asking price, financing, whether an offer has already been made, where they are in the transaction, what worries them, and which questions are still unanswered.

A seller comes with a different situation. Relevant context may include ownership, whether the property is already listed, current asking price, known issues, previous buyer objections, work carried out, and what they want to improve before the next stage of the sale.

Those differences continue into the backend as separate validated data models rather than one oversized form full of unrelated optional fields. The public experience follows the same logic: calmer decisions for buyers and better preparation or regained control for sellers.

  1. Verify
02

[ Payment had to unlock the right booking ]

A successful Stripe payment is an event, not the whole booking.

When somebody starts checkout, the application first creates its own booking reference together with the selected service and expected amount. That reference follows the transaction into Stripe.

The browser returning from checkout is not enough evidence that the booking should continue. The server still needs to know which booking was paid for and whether the payment matches what the application expected.

The Stripe webhook verifies the completed session server-side, including the booking reference, payment state, amount, and currency, before changing the booking to paid. Webhook events are recorded as well, because Stripe can legitimately deliver the same event more than once. State updates are protected so two requests cannot silently complete the same transition.

Only after payment is confirmed does the client receive access to the next part of the process.

03

[ Content and client data needed a clean boundary ]

Private property information should not live beside website content.

A booking can include contact details, property addresses, asking prices, transaction status, financing context, concerns, access information, and other details about the property. Clients can also provide documents for the advisor to review before the appointment.

Resend
Application
Sanity

Public content

Website & CMS

Neon

Private operations

Booking & client data

Private files

Client documents

Application
Resend
Sanity

Public content

Website & CMS

Neon

Private operations

Booking & client data

Private files

Client documents

Public content and private client data remain separated by design

Stripe processes payments, Cal handles availability and appointments, and Resend handles transactional email. Each external service stays focused on its own job.

Sanity can change the website. It doesn’t need access to a client’s property file.
04

[ The appointment starts before the visit ]

The form exists so the paid appointment starts with context.

Once the booking is paid and access is verified, the client can see available appointment times and choose a slot. From there, the process moves into the buyer or seller intake.

The form is intentionally detailed because the information has a job to do. It tells the advisor what stage the client is at, what is already known, where the uncertainty is, and what should be reviewed before the appointment.

Clients can also attach supporting documents. Uploads are checked on the server, not only in the browser: file size and allowed formats are validated, and the file contents are checked rather than relying only on the filename or MIME type.

Once the final submission succeeds, the appointment is created and connected to the booking, client information, and intake. By the time the advisor opens the appointment, the administrative preparation should already be done.

The form isn’t there to collect more data. It is there so the paid appointment starts with context.

[ Production reality ]

A clean booking flow gets less clean once real people start using it.

  • Stripe can send the same webhook again.
  • Checkout can expire before payment.
  • A verification code can expire.
  • A form can be submitted more than once.
  • A file can have the right extension but the wrong contents.
  • A client may need to request a refund after payment.

None of those problems belongs to one particular screen. I modelled the booking state centrally so the backend can decide what is allowed based on what has already happened.

That includes payment state, access and session state, selected service, appointment state, and submission status. The client does not need to create a permanent account just to use a one-off service: paid booking access uses time-limited credentials and a short authenticated session, with email verification available when automatic access is no longer valid.

Refund requests are tied back to an existing booking and verified through the booking email rather than accepted as anonymous messages.

[ The outcome ]

The advisor doesn’t have to reconstruct a booking from five different tools.

A client can move from understanding the service to paying, choosing a time, and preparing the property visit without a manual hand-off between every step.

The advisor receives the appointment together with the context needed to prepare for it instead of piecing together a Stripe payment, calendar event, email conversation, form submission, and document exchange.

The public website remains editable through Sanity, while private booking data and documents stay within the operational side of the system.

Less time putting the booking together. More time spent on the actual property decision.

[ What I owned ]

I worked across the complete product.

I started with how the service should work online and carried that through product design, frontend, backend, data architecture, and production setup.

That included the buyer and seller journeys, payment and booking state, private data model, secure booking access, calendar integration, structured intake, private file handling, transactional emails, Sanity content architecture, legal and consent implementation, SEO, and deployment.

  • Product & UX/UI01
  • Frontend02
  • Backend & APIs03
  • Data architecture04
  • Payments05
  • Booking & scheduling06
  • Security & access07
  • Forms & file handling08
  • CMS & content modelling09
  • Transactional email10
  • SEO & consent11
  • Infrastructure & production12
  • Product & UX/UI01
  • Frontend02
  • Backend & APIs03
  • Data architecture04
  • Payments05
  • Booking & scheduling06
  • Security & access07
  • Forms & file handling08
  • CMS & content modelling09
  • Transactional email10
  • SEO & consent11
  • Infrastructure & production12

[ Built with ]

Application
Book your slot
  • Details
  • Buyer context

    • Financing status
    • Transaction stage
    • Concerns & open questions
    • Decision priorities

    Seller context

    • Listing / sale status
    • Property history & work
    Review & submit
    One booking flow, with context shaped around the client’s side of the decision
    Buyer and seller share the product. They don’t share the same questions.

    Choose a service

    Pay securely

    Payment confirmed

    Payment not completed

    Booking link is not sent

    Receive booking link

    Server verification—not the browser return—unlocks booking access
    Stripe confirms the payment. The booking record decides what happens next.
    Most of this work is invisible when the booking goes well. That’s the point.
  • Shadcn UI
  • Motion
  • Private data
    • Neon
    Private files
    Content & publishing
    • Sanity
    Payments & scheduling
    Communication & protection
    • Resend
    Known issues & buyer objections
  • Desired outcome