← All projects

Psic. María Fernanda Ramírez

A white-label booking platform for psychology practices — public scheduling with Google Calendar + Meet, a no-login patient portal, and branding driven by config. NestJS 11 + Prisma + Angular 22, live in production for a clinical psychologist in Guadalajara.

NestJSPrismaPostgreSQLAngularRedisSSR

A psychology practice lives on its appointments, but schedules them however it can: a WhatsApp thread, a notebook, and whatever the person answering the phone remembers. The patient who wants to reschedule at eleven at night can’t; the reminder depends on someone thinking to send it; and the online session is one more message with a link pasted in by hand. Remanso is a white-label booking platform for psychology and therapy practices that collapses all of that into a single flow — and its first deployment is live in production for a clinical psychologist in Guadalajara, live at psicfernandaramirez.com.

What it does

It covers the full lifecycle of an appointment, from the moment a patient books it to the moment they walk into the session:

  • Public booking. The patient picks a service, a modality (in-person or online), a consultorio when there’s more than one, and an available slot — all without creating an account. Availability is computed against the real schedule, not a static list.
  • Patient self-service by code. Every appointment generates a code. With it, the patient cancels or reschedules without logging in, downloads the event to their calendar (.ics), and saves the practice’s contact (.vCard) — no passwords to forget.
  • Automatic Google Calendar + Meet. Once the psychologist connects her Google, every confirmed appointment creates the event on her calendar, and online sessions generate their own Meet link — no links pasted by hand.
  • Phone wallet pass. The patient adds their appointment to Apple Wallet or Google Wallet —depending on their device— as a pass generated on demand, carrying the time, the place and the session link.
  • Branded transactional email + reminders. Confirmations, reschedules and reminders go out as email branded for the practice, and reminders are scheduled in the background so they land on time.
  • WhatsApp click-to-send. For the moments that genuinely warrant a human, a button opens WhatsApp with the message pre-filled — no heavy API integration for an MVP.

Under the hood

Remanso is built around one idea: there’s one product, but each practice sees it as its own. Everything interesting about the architecture falls out of taking that decision seriously.

Real white-label, driven by configuration. The client’s name isn’t written into the code anywhere. The branding — practice name, colors, contact, services, hours — lives in config and environment variables, so standing up a new practice is a config change, not a fork of the codebase. That forces a healthy discipline: if a client name leaks into a template or an email, it’s a bug, not an option.

The patient never authenticates. The entire patient experience — book, cancel, reschedule, download the appointment — runs against a public code per appointment, not an account. It’s deliberate: nobody is going to create a user to ask for a therapy appointment, and forcing them to is the surest way to lose the booking. The code is the credential, with its own narrowly-scoped surface on the server.

Google integration kept properly encapsulated. The link to Google Calendar and Meet goes through OAuth, with the psychologist’s token stored server-side, and a dedicated integration model the admin panel turns on and off. Event and Meet creation happen when the appointment is confirmed — not in the patient’s request path.

The Wallet pass, reused carefully. The patient saves their appointment to Apple Wallet (a signed .pkpass) or Google Wallet, depending on their phone. Both passes were ported from another of my products and share the same issuer and credentials, but they carry a guard prefix that separates Remanso from anything else living under that issuer. Reusing infrastructure is cheap; reusing it without isolation is how you end up with one product’s pass showing up in another.

Slow work leaves the request. Reminders and email run on Redis-backed queues (Bull), scheduled with configurable offsets. The patient’s booking responds fast; the system handles notifying on time in the background.

UTC-consistent wall-clock time. Wall-clock times are handled with a single timezone convention end to end, so the appointment the patient sees, the one that lands on the psychologist’s calendar, and the one that travels in the .ics and the pass are the same time — none of the classic one-hour drift that shows up when each layer interprets the date its own way.

The stack

  • Frontend — Angular 22 with server-side rendering (SSR) and Tailwind 4, with a watercolor and “liquid glass” interface; internationalization via Transloco; a custom booking calendar (no dependency), .ics and .vCard generation.
  • Backend — NestJS 11 in strict TypeScript on Node.js, REST API.
  • Data — PostgreSQL via Prisma; Redis for Bull job queues (reminders and email).
  • IntegrationsGoogle OAuth + Calendar + Meet (automatic events and online sessions), Apple Wallet + Google Wallet (the appointment pass, chosen by device), Resend for branded transactional email over HTTPS, and WhatsApp click-to-send.
  • Branding — per-client white-label configuration (name, colors, contact, services, consultorios and availability) via config and environment variables.
  • Platform — backend on Railway (with managed Postgres and Redis), frontend on Firebase App Hosting with a custom domain; Prisma migrations at boot.

Worth noting

I built Remanso end to end — the frontend, the backend, the data model, the Google integrations, the white-label layer and the deployment — and its first client is live in production. The decision that defines the project isn’t any single integration: it’s that it’s designed as a product, not a site for one client. Rebranding for the next practice is configuration, not a fork.

And where it made sense for an MVP, I chose simple on purpose: manual WhatsApp and a transactional email API (Resend) over heavy integrations, because the job of a first deployment is to validate the flow that creates value — book, remind, make the session — not to accumulate plumbing nobody asked for yet.

Coffee & talk?

Like what you just read? I build products like this end to end — and I'm always up for a conversation. Let's talk about yours, or just trade notes over coffee.