Home

UnCierre

Year
2023–2025
Type
Work project · Conversion
Status
Engagement Apr 2024 – Dec 2025
Website
uncierre.com
Stack
  • Node.js and TypeScript
  • Express
  • Next.js and React
  • Expo and React Native
  • PostgreSQL
  • Hasura (GraphQL)
  • RabbitMQ
  • Knex and Prisma ORM
  • Jest and Playwright
  • Turborepo

Summary

UnCierre is the platform real-estate developers use to sell and rent their projects. It covers the whole commercial life of a building, from the inventory of units to the last payment of a sale or a rent.

Developers load their projects and units, with parking spaces and storage as extras. Their sales team quotes a unit with a down-payment plan, can hold it for a customer for a few days, and turns the quote into a reservation with its installments and payments. Supervisors then take each deal through file review, contract signing, credit approval and delivery. Rentals live in the same platform, with escalations, variable rent based on the tenant's sales, extensions and endings, and customers follow their deals and pay from a mobile app.

The product is made of three parts:

  • A commercial dashboard for admins, supervisors and sellers.
  • A customer app on the phone, where buyers and tenants follow their deals live and pay.
  • A set of services behind both, where every change to a sale is stored as an event.

I worked on UnCierre at Conversion as a Mid-level Software Engineer, from April 2024 to December 2025. I wrote most of the reservation, rental and notification services, the quoting engines, a large part of the dashboard and the customer app. This case study shows the product through its flows and diagrams.

+40%
sales growth
-30%
release cycle time
1,500+
of my commits in the platform

Context & role

  • Company: Conversion
  • Product: A commercial dashboard, a customer app and the services behind them
  • My role: Mid-level Software Engineer
  • What I built: Most of the reservation, rental and notification services, the sales quoter, the reservation wizard and the rental quoter, the shared core library, a large part of the dashboard and the customer app
  • Duration: April 2024 to December 2025

Problem

Selling and renting property involves long, money-heavy processes. A reservation can last months, with installments, discounts, extras and several sellers along the way, and a rental carries its own installments, escalations and endings. A system that only stores the current state cannot answer what changed, when and by whom, and that is exactly the question a sales team and a buyer ask when money is involved.

The scope of the platform shows where that hurts:

  • Sellers need to quote fast, hold a unit for a customer and turn the quote into a reservation without losing the conditions they agreed.
  • Supervisors need to confirm each payment and move each deal forward, with a record of every step.
  • Buyers and tenants need to see their installments and pay without calling the sales office.
  • The platform itself had to grow out of an earlier one, breaking a monolith into services that could change at their own pace.

The seller carries most of that weight. Every deal starts with them, and a unit quoted twice or a hold that never expires turns into a conversation with an upset customer, so most of the sales side was designed around keeping units, quotes and reservations consistent on their own.

Users & context of use

Five profiles shape the platform, from the people who sell a unit to the tenants who pay their rent from a phone.

Seller

Quotes units with discounts, bonuses and extras, holds them for a customer, creates reservations and registers payments.

Commercial dashboard

Supervisor

Confirms, cancels or undoes payments and moves each reservation through its stages.

Commercial dashboard

Admin

Configures projects, imports units, sets discounts, bonuses and limits, and manages the commercial team and notifications.

Commercial dashboard

Buyer

Reserves a unit, pays it in installments and receives quotes, statements and receipts.

Customer app, email and WhatsApp

Tenant

Pays rental installments with proof, reports sales for a variable rent and follows the contract.

Customer app

The moments that shaped the design

  • A seller with a customer in front of them quotes a unit and wants to hold it. Nobody else should be able to sell it meanwhile, and the hold has to end on its own if the customer walks away.
  • A supervisor reviewing payments needs to undo a mistake, but only the last one, so the history of a deal never gets rewritten.
  • A tenant paying from the phone uploads the proof and expects to see the installment updated, live.
  • An admin answering a buyer's question needs to know exactly what happened to a reservation, months later.

Goals, success metrics & constraints

Goals

  1. Let the commercial team quote, hold and reserve units faster, without double-selling.
  2. Keep the full history of every deal, so any change can be explained.
  3. Let buyers and tenants follow and pay their deals on their own.
  4. Break the earlier monolith into services that can change independently.
  5. Ship changes to production faster, with tests the team trusts.

How success was measured

Two results came out of the work: the quote and booking engines opened new revenue streams and sales grew by 40%, and standardizing test-driven development, together with the rest of the work, shortened production release cycles by 30%.

Constraints

  • A legacy to carry forward. The platform grew out of an earlier one, so data and some packages from it had to keep working while the services were split.
  • Money in more than one currency. Payments and rents carry an equivalent amount and an exchange rate.
  • Many projects, each with its own rules. Limits on quote and hold days, notification channels, webhooks and PDF templates are configured per project.

Process & prioritization

From problem to scope

The work started from the life of a deal: a unit is quoted, held, reserved, paid and delivered, or rented and paid month by month. Each step became a capability, and each capability got the place in the architecture its risk called for, with the money-critical reservation at the center.

What the platform covers

AreaWhat it enables
InventoryProjects, towers and units with parking and storage as extras, imported from spreadsheets, and a tower view of units by status.
QuotesDown-payment plans with editable installments, extra paydowns, discounts, bonuses and an early-payment discount.
HoldsA unit held for a customer for a limited number of days, released by a scheduled job.
ReservationsA three-step wizard, installments, payments, sellers, extras, notes and a status stepper with a full history.
CollectionsInstallments on time, partial, paid or delayed, by project.
RentalsRental quotes, agreements with escalations, variable rent from sales reports, payments, extensions and endings.
NotificationsEmail and WhatsApp by role and event, and outbound webhooks per project.
DocumentsQuotes, receipts, statements and rental documents as PDFs, per project.
Customer appReservations and rentals live, installments, payments with proof and sales reports.

What waited

  • Two planned services, for authentication and for clients, were not built.
  • Part of the dashboard still uses the older styling while it moves to the shared component library.

Design decisions

The decisions that most shaped the product, made by the team and designed by the company's product designer. Each one is shown as a flow or a diagram.

A reservation that runs on its own steps

Problem. A sale passes through quoting, reserving, paying and a long list of paperwork, and each step belongs to a different person.

Decision. The seller quotes and reserves, the platform reacts to each step, and the supervisor confirms payments and moves the deal forward. The first payment opens the reservation by itself.

Trade-off. More states to model, and some steps that only a supervisor can take.

In the product. Creating a reservation reserves the quote and the unit and notifies everyone involved, and the supervisor sees exactly which stage comes next.

From a quote to a delivered unitThe seller, the platform and the supervisor, each with their part.

A hold that ends on its own

Problem. A seller who holds a unit for a customer blocks every other seller. If the customer never comes back, the unit stays blocked until someone remembers.

Decision. Holding a unit marks every other quote for it as lost. A scheduled job releases the hold after the project's limit of days, and the lost quotes come back on their own.

Trade-off. Quotes have more states, and a lost quote can come back to life.

In the product. When a hold expires, the unit is available again and each lost quote goes back to open, or to expired if its own date has passed.

A hold on a unitHolding a unit for a customer, and what happens when the hold expires.

Rentals that close themselves

Problem. A rental is a long series of payments, sometimes tied to the tenant's sales, and its ending is easy to miss.

Decision. The tenant pays and reports sales from the app, staff confirm each payment, and the platform warns when two installments remain and closes the rental when everything is paid.

Trade-off. Variable rents recalculate installments whenever a report arrives.

In the product. Closing an agreement marks the unit as rented and closes the other offers on it, and finishing the rental frees the unit again.

A rentalFrom the quote to the last installment, with the tenant paying from the app.

Two ways to end a deal

Problem. A customer who desists and a reservation created by mistake are very different, but both remove a deal from the pipeline.

Decision. Desisting marks the reservation as lost and releases the unit. Deleting is final: the unit becomes available and its quotes come back.

Trade-off. Two actions the team had to learn to tell apart.

In the product. Each one notifies the right people and leaves its trace in the reservation's history.

A reservation, step by stepFrom the first payment to delivery, and the two ways a deal can end early.

The customer sees the deal live

Problem. Buyers and tenants need to know how much they owe and whether their last payment arrived, without asking the sales office.

Decision. The customer app subscribes to the same read models the dashboard uses, so a confirmed payment appears on the phone as soon as it is confirmed.

Trade-off. Live subscriptions to keep open for every signed-in customer.

In the product. Buyers and tenants see their installments, payments and documents, and tenants pay with a proof and report sales from the app.

Design system

The dashboard and the customer app share one visual language, created by the company's product designer, and the dashboard's components live in a shared library built on Tailwind and shadcn.

Foundations

  • Two typefaces. Poppins for titles and Roboto for the interface, tables and amounts.
  • A deep violet and a teal. Violet for the brand and the main actions, navy for structure and two teals as accents.
  • A customer app with two themes. The app follows the phone's light or dark theme, with a palette for each.
  • Status colors for money. Paid and on time, partial and delayed always look the same, in collections and in the app.
  • One radius scale. A short scale of radius values shared by every component.
FoundationsTypography, color, status colors, radius and spacing of the dashboard and the customer app.

Built into the apps

I built the customer app with its light and dark palettes, and worked on the dashboard as it moved onto the shared component library. A component added to the library is available to every screen, which is how the older parts of the dashboard move over one by one.

From design to code

As a Mid-level Software Engineer, my work was turning the design and the business rules into a working platform. This section explains how it is organized, in terms of what each part does.

Architecture

The repository is a monorepo with the dashboard, the services and shared packages for the quoters, the reservation wizard, the tower view, the tables, the components and a core library. The apps talk to one GraphQL layer, which serves the read models with live subscriptions and forwards each change to the right service as an action.

The services follow a strict hexagonal architecture: the domain stays independent from the framework, the databases and the messaging. They talk to each other through a message bus, so notifications and inventory react to a sale without slowing it down, and the event store, the read models and the rental data live in separate databases.

ArchitectureThe two apps, the GraphQL layer, the services and the data behind them.

Event sourcing for the money

Reservations and customers are event-sourced. A command rebuilds the reservation from its events, applies the business rule and appends a new event. A trigger updates the read model, and a map of post-actions runs the side effects of each event, such as reserving the quote and the unit or calling a project's webhook.

That history is why the platform can explain any deal months later, and why a supervisor can undo the last payment without rewriting what came before.

How a change is writtenFrom a mutation to the event store, the read model, the side effects and the other services.

Inventory that follows the deal

Quotes, units and rentals change state in step with the deals around them. Holding, reserving, desisting, deleting or renting cascades to the unit and its extras automatically, so the inventory never says a unit is free when it is not.

Life cyclesThe states of a quote, a unit and a rental, and what moves each one.

Quality and delivery

Test-driven development was standardized across the services, with unit tests in each service and end-to-end suites for the main flows: quotes, reservations, rentals, payments, sign-in and inventory. Each service ships on its own, so a change to rentals never waits for a change to sales.

Technical decisions

DecisionWhyTrade-off
Hexagonal architectureBusiness rules stay independent from frameworks, databases and messaging.More structure up front, with ports and adapters to write.
Event sourcing for reservations and customersDeals are long-lived and every change must be explainable.An event store, projections and handlers to keep in sync.
CQRS with GraphQL readsWrites follow business rules, and the apps read shaped projections.Two models to maintain.
A message bus between servicesNotifications and inventory react without blocking a sale.Routing to design and a broker to run.
Separate databases per concernSales history, read models and rentals evolve independently.Consistency across databases has to be designed.
Post-actions as a mapSide effects of each event are declared in one place and logged.One more place to look when an event misbehaves.

Results

The quote and booking engines opened new revenue streams, and sales grew by 40%. Standardizing test-driven development, together with the rest of the work, shortened production release cycles by 30%.

Day to day, the commercial team covers the whole life of a deal in one place: inventory, quotes, holds, reservations with their installments, collections, rentals, payments, receipts and notifications. Buyers and tenants follow their deals and pay from the customer app.

Learnings & next steps

Next steps

  • Build the authentication and client services that were planned.
  • Finish moving the older parts of the dashboard onto the shared component library.

What I learned

  • Event sourcing pays off where money is. Keeping every change as an event added moving parts, but it made every question about a deal answerable, which is what a sales team needs most.
  • Consistency is a design problem, not a database feature. Holds, reservations and rentals all touch the same units, and keeping them consistent across services meant designing each cascade explicitly.
  • Tests change how fast a team dares to ship. Standardizing TDD felt slower at first, and it is what let releases get shorter.