Markado
Service scheduling platform with real calendar and payments
In plain English
A booking website where a professional shares one link, clients pick a free time slot, and the meeting plus the payment are handled automatically.
My role
Solo full stack developer
Timeline
Ongoing
Team
Solo
Status
Case study
Design
Product tour




Section 01
The problem
Booking a service still runs on message threads. Someone asks for a time, the provider checks their calendar, they go back and forth, and then payment happens somewhere else entirely. Every step is manual and every step can fail: double bookings, forgotten meetings, unpaid sessions.
Section 02
How I approached it
I built a single scheduling surface that owns availability, the calendar event, and the money. The provider defines their working rules once. Everything downstream — the free slots a client sees, the Google Calendar entry, the Meet link, the Stripe charge — derives from that one source of truth.
Outcome
A booking link that turns a conversation into a confirmed, paid, calendar-synced appointment in about thirty seconds, with no manual step for the provider.
Section 03
Going deeper
What it actually does
A provider signs up, connects their Google account, and describes when they work: days, hours, buffer between sessions, how far in advance people can book. Markado turns those rules into a public page. A client opens it, sees only genuinely free time, picks a slot, pays, and receives a calendar invite with a video link. The provider never touches anything.
Why availability is the hard part
Showing free time sounds trivial until you account for timezones, existing events in an external calendar, buffers, minimum notice, and two people trying to book the same slot in the same second. Availability is computed on the server from working rules plus live Google Calendar data, and the final write is guarded so the second person to click gets a clear 'just taken' message instead of a silent double booking.
Type safety end to end
The whole app speaks one type system. tRPC means the frontend calls backend procedures as if they were local functions, with argument and return types checked at compile time. Prisma generates the database types. If I rename a column, the build fails in the UI file that used it. That eliminates an entire category of bugs that normally reach production.
Section 04
The build process
Map the booking journey
I wrote out every state a booking can be in — requested, confirmed, paid, rescheduled, cancelled, no-show — before writing code. That state list became the database schema.
Model availability first
Availability was built and tested as a pure function: given rules, existing events, and a timezone, return open slots. Isolating it meant I could test edge cases like DST transitions without spinning up a UI.
Layer the integrations
Google OAuth, then Calendar read, then Calendar write with Meet conferencing, then Stripe. Each integration shipped behind its own boundary so a failure in one doesn't take down the booking flow.
Automate the pipeline
GitHub Actions runs typecheck, lint, and tests on every push, then builds the Docker image. Deploys are a merge, not a ritual.
Section 05
How the pieces fit together
Each layer has one job. Read it top to bottom — that's roughly the path a request takes through the system.
Next.js App Router
Server components for the public booking page, client components for the interactive slot picker.
tRPC procedures
End-to-end typed RPC layer — no hand-written fetch clients, no drifting API contracts.
PostgreSQL + Prisma
Relational schema for users, event types, availability rules, and bookings with migrations in version control.
Google Calendar / Meet · Stripe
OAuth 2.0 for calendar access, conferencing auto-created per booking, Stripe for checkout and webhooks.
Docker + GitHub Actions
Reproducible container builds, automated checks, and continuous deployment.
Section 06
What it does
Multi-step authentication
Signup is split into deliberate stages so the account, the calendar connection, and the payment setup each get a clear, recoverable step.
Live availability engine
Slots are computed against real calendar data, timezones, and buffer rules — never a static list.
Automatic video meetings
Every confirmed booking creates a Google Calendar event with a Meet link attached for both parties.
Payments at booking time
Stripe checkout runs inside the booking flow, so a confirmed slot is a paid slot.
Section 07
The hard parts
Timezones
A provider in Rio and a client in Lisbon must see the same moment in their own local time. Everything is stored in UTC and converted only at the display edge, with the timezone captured explicitly at booking.
Race conditions
Two clients can request the same slot simultaneously. The booking write revalidates availability inside the transaction, so the loser gets a clean error rather than a corrupted calendar.
External API failure
Google and Stripe both go down occasionally. Failures are isolated per integration and surfaced honestly instead of leaving a booking in an unknown state.
Section 08
What I took away
- Modelling the state machine before the schema saved weeks of migration churn.
- Pure functions for business rules are worth the extra indirection — they are the only parts you can test cheaply.
- End-to-end type safety pays for itself the first time you rename something.
Type
SaaS product
Integrations
Google Calendar, Meet, Stripe
Auth
Multi-step
Deploys
CI/CD via GitHub Actions
Let's build something worth shipping
Available for freelance projects, full-time roles, and technical consulting. Tell me what you're building and I'll tell you honestly whether I'm the right person for it.
Based in Rio de Janeiro, Brazil · Working with teams in any timezone · Fluent in English and Portuguese