Plumaa
A mental health platform for people, psychologists and companies
I joined when Plumaa was still just an idea. I picked the stack, designed the database and built the backend of a mental health platform with three audiences: people looking for therapy, psychologists and companies.
In 30 seconds
- The only backend developer since the idea stage: I picked the stack (NestJS, Prisma, PostgreSQL) and designed the database.
- Five roles with permissions decided in the backend, Stripe payments, Google scheduling and an AI pipeline for session notes.
- In production, with ~100 active accounts; the AI summary saves each psychologist 3 to 8 hours a week.
- When
- Jan 2026 — present
- Role
- Full-Stack Developer · sole backend developer
- Team
- up to 3 developers
- Stack
- React (Vite), NestJS, Prisma, PostgreSQL, Graphile Worker, Stripe, Google APIs, Claude, Deepgram
Context
Plumaa is a mental health platform. People buy single sessions or plans to see partner psychologists; psychologists manage their schedule and sessions; and companies use a separate product to map psychosocial risks, as required by Brazil's NR-1 workplace regulation.
It's a small startup: the tech team peaked at three people. Today there are about 100 active accounts across clients, psychologists, companies and their employees.
The problem
A single backend had to serve five profiles with very different views of the same data, and some of that data is health data. A psychologist can't see another's data, a company can't see its employees' individual answers, and no one but the admin can get near the rest.
On top of that: billing for sessions and subscriptions, scheduling across time zones, and psychologists spending hours a week writing session notes by hand. All with a tiny team, at startup speed.
My part
I was the only backend developer. I chose the stack, designed the database and the access and storage strategy, and helped build the team by running the technical interviews. The other developers owned the frontend; I reviewed their work on staging and handed over every API change with its Swagger docs.
- Access control for the five profiles: client, psychologist, company, employee and admin.
- Stripe payments: single sessions, plans with benefits and company subscriptions.
- Scheduling with Google Calendar and sign-in with Google.
- The NR-1 B2B product: a questionnaire shared by public link with access checks, and the risk scoring in the database.
- An AI pipeline that transcribes the session and drafts the clinical notes.
- A system event log (session started, transcription started, payment made) for the admin dashboard.
- Unit and integration tests covering every backend route and service.
- Infrastructure: backend and database on Digital Ocean, frontend on Vercel, staging mirroring production.
Technical decisions
Permissions always on the backend
The session cookie says who the user is and which profile they have. Before any query reaches the repository, a layer decides which tables and columns that profile may read. Anything outside it returns 404, without even confirming the resource exists.
Postgres for everything, no Redis
Background jobs run on Graphile Worker, a queue stored in PostgreSQL itself. At today's load, that's one less service to pay for, monitor and keep running.
Stripe Checkout and idempotent webhooks
Payment happens on Stripe's page, so card data never touches our server. Access is only granted when the webhook arrives, and every transaction is recorded: if the same event arrives twice, it's ignored.
Schedules in UTC
Every time slot is stored in UTC and converted to the psychologist's working time zone. Booking is an attempt: the slot only moves on to payment if it's still free.
With Google, two scopes: everyone uses sign-in, but only psychologists grant calendar access.
Async, anonymized AI
When a session ends, a job takes over: it transcribes with Deepgram, strips out the personal data the database already knows about and sends the text to Claude to structure the notes. The psychologist gets a draft instead of a blank page.
Small, but ready to grow
One machine per service, on the simplest plan, because demand didn't call for more. The database only accepts connections from the backend and is backed up daily, and staging replicates the whole ecosystem from the development branch.
Architecture
Outcome
The platform is in production, with about 100 active accounts across the three audiences. The AI session summary saves each psychologist who uses it 3 to 8 hours a week, time that used to go into writing notes from memory.
The boleto bug
For the subscriptions feature we spent days testing on staging: credit, debit, declined, expired, insufficient funds, timeouts. We shipped, it worked. Then a customer clicked “pay with boleto” (a Brazilian bank slip): someone had turned that option on directly in the Stripe dashboard, and the version we tested didn't have it.
We reverted the setting and helped the customer finish paying. The lesson: there will always be a scenario you didn't test. The goal isn't zero bugs, it's zero impact.