← All projects

Case study

Naora: online booking where a Pix deposit holds the time

A booking app for salons, barbershops and beauty studios. The client picks a service, a day and a time, and the time is only hers after a small deposit paid by Pix. The business gets a dashboard, and the deposit goes straight to its Mercado Pago account.

My role
Product, UX and UI, development, payments, testing and deploy
When
October and November 2026
Stack
Next.js 16, React 19, TypeScript, PostgreSQL (Neon), Prisma 7, Auth.js v5, Mercado Pago (Pix, OAuth, subscriptions), Tailwind CSS, Ipê, Jest, Cypress, Docker on Render

The problem

Small beauty businesses in Brazil book clients by WhatsApp. A client says yes, the time is kept for her, someone else is turned away, and then she does not come. The chair stays empty and that hour is lost.

A deposit changes the commitment: whoever pays shows up, and whoever does not pay frees the time for someone else. Pix makes that deposit instant and cheap, so the whole flow can happen on a phone in under a minute.

Naora is also a real micro-SaaS, built to run in production at zero cost. On the Free plan it keeps 15% of each deposit; the Pro plan costs R$ 39.90 a month with no fee.

What I built

Booking page on a phone: the service Escova modelada, 60 minutes, R$ 45, and a grid of the next two weeks with the free days highlighted.
Choosing a day on a phone.
Deposit page in the dark theme: the heading “Falta só o sinal”, a Pix QR code and the copy-and-paste code of the demo.
The Pix deposit, dark theme.
Owner dashboard of Studio Ana Luz: the public page address and the next bookings, each with the client name and WhatsApp number.
Owner dashboard, with the bookings that already paid the deposit.

Decisions worth explaining

The same time is never sold twice

Two clients can tap the same time in the same second. The check and the insert run in one transaction holding a Postgres advisory lock for that business, so the second request waits, sees the first booking and is told the time is gone. An integration test fires 8 requests at once and expects exactly one to win.

The webhook only says “look again”

A notification from Mercado Pago never confirms a booking by itself. Naora reads the payment back from Mercado Pago with the business's own token and confirms only when it says approved. A forged notification, or one sent to another business's address, changes nothing. Each charge uses the booking id as its idempotency key.

A late payment is recorded, not double-booked

If a client pays after the hold ended and someone else already took the time, the payment is saved and shown to the owner, and no second booking is created.

Times live in the business's time zone

Slots are built in the business's own time zone, not the server's, which runs in the United States. Unit tests cover São Paulo and New York across daylight saving time.

No online booking without the deposit

An early version let a business without Mercado Pago take bookings with the deposit “arranged in person”, and the platform's fee simply disappeared. Now a rule decides when a service can be booked online, and the server, the public page and the dashboard all follow it.

Secrets stay secret

Mercado Pago tokens are stored encrypted with AES-256-GCM and refreshed before they expire. The OAuth state is signed with HMAC and tied to a nonce in an HttpOnly cookie. Each page gets a new nonce for its Content Security Policy.

Quality, measured

Checked on every pull request. Last checked on November 4, 2026.

AreaResultHow it is checked
Tests107 unit · 38 integration · 24 end-to-endJest, PGlite (real Postgres in memory), Cypress against the production build
Accessibility0 axe violations · WCAG 2.2 AAcypress-axe in Portuguese and English, light and dark, and a 320px screen
Concurrency1 of 8 simultaneous bookings winsIntegration test against the real transaction and lock
Security headersNonce-based CSP, HSTS, nosniff, frame-ancestors noneEnd-to-end test that reads the response headers
CodeTypeScript strict, 0 ESLint warningsTypecheck and lint on every pull request

The QA cycle

Naora is live, and its QA cycle is running now. The test plan has 38 test cases across 11 modules, a risk matrix that puts money first, and clear entry, exit and suspension criteria.

The rounds go from safe to real: the demo and accounts first, then a real Pix between two Mercado Pago accounts to confirm the 15% split on the statement, then the Pro subscription, and finally feedback from people outside the project in an open beta.

What I learned

  • A business rule can hide in one friendly sentence. “The deposit is arranged in person” looked kind and quietly removed the revenue.
  • Behind a proxy, a server does not know its own address. Redirects now use the public site address, after Google sign-in sent people to an internal one.
  • A small visual change can change what a test sees. A sticky header made Cypress treat the skip link differently, and the right fix was in the page, not the test.

Try it

No sign-up needed: click “Try the demo” in the header, create a pretend salon and book as a client. The demo Pix is simulated and nothing is charged. It runs on Render's free plan, so the first visit can take about a minute. Open Naora.