Petzara started with a simple observation: pet shops that deliver great service but get stuck in manual operations. Schedules in a notebook, customer history in WhatsApp, a team with no visibility. The problem was clear. The solution had to be built.
Why a SaaS, not an app?
The first decision was choosing web over a native app. The reason: pet shops use multiple devices — the front desk computer, the groomer's phone, the manager's tablet. A responsive web system solves that without the overhead of two codebases.
On top of that, the web has instant deploys. Updating a web system is invisible to the user. Updating a native app requires store approval and the user updating manually.
The hardest decision: modeling the schedule
The heart of Petzara is the appointment system. And it has to be reliable — two appointments at the same time with the same groomer is a serious error that hurts both the customer and the business.
The solution wasn't just front-end validation. The database has a constraint that physically prevents two conflicting appointments. Front-end validation exists for immediate feedback; the database one exists as the final guarantee.
-- Constraint que impede conflitos de horário por funcionário
CREATE UNIQUE INDEX unique_appointment_slot
ON appointments (employee_id, date, time_slot)
WHERE status != 'cancelled';
The calendar challenge
Building an interactive calendar from scratch is complex. We used FullCalendar, but integrating it with our data model required significant customization.
The calendar needed to:
- Show appointments in real time (WebSocket)
- Filter by employee with different colors
- Support dragging appointments between time slots
- Work well on mobile (the main device in use)
Mobile drag-and-drop was the most laborious part — touch events behave differently from mouse events in calendars. The solution was an abstraction layer that maps touch events to drag events.
Notifications: what seemed simple
Sending a WhatsApp appointment confirmation seems simple. In practice, it involves:
1. A message queue so the API doesn't get overloaded 2. Rate limiting per phone number 3. Retry on failure 4. A log of sent messages 5. Opt-out for customers who don't want to receive them
What started as "just send a message" became a microservice of its own.
What we learned from the first users
The pet shops that used it in the first few weeks showed us something unexpected: the most-used feature wasn't the schedule — it was the pet's history.
"Which product did I use on Buddy last time?" "Is this dog allergic to any product?" "How long does it take to groom him?"
That made us prioritize pet records with notes fields, service history and even photo uploads. The product got better because of real usage, not planning.
Final stack
- Front-end: React + TypeScript + Tailwind CSS
- Back-end: Node.js + Express
- Database: PostgreSQL with Prisma ORM
- Real time: WebSocket for schedule updates
- Notifications: WhatsApp Business API + Redis queue
- Deploy: Vercel (front-end) + Railway (back-end + database)
- Payments: Stripe for monthly subscriptions
What I would do differently
If I were starting today, I'd use Next.js with the App Router from the start to get SSR and SEO with no extra configuration. I'd also implement multi-tenancy at the database level (schema per tenant) instead of row-level security, which complicates queries.
But those are architectural improvements. The core of the product — solving the scheduling problem for pet shops — works well and is in real use.
That's what matters.