FULL STACK · MOBILE + WEB DEVELOPER

An end-to-end management platform built specifically for pet care operators — dog boarding kennels, grooming studios, daycare centers and training facilities. The core promise: replace the chaos of WhatsApp bookings, paper registers and spreadsheet invoices with a single, beautiful app that feels as warm as the business it serves. Two layers ship it: a Flutter mobile app the owner and staff live in daily, and a FastAPI Python backend powering real-time data, auth, file storage, reporting and background jobs.
Pet boarding owners aren't typical B2B SaaS customers — they're emotionally invested in animals first, business second, often solo operators who are caretakers by morning and accountants by night. Before Petsy their workflow was WhatsApp for bookings, a notebook for kennels, Tally for invoices, Sheets for reports — none of it talking to each other. They're trust-driven, not feature-driven: open an app, see what needs to happen today, get back to the dogs. That psychology shapes every decision — calm, warm and reliable, never enterprise-cold or feature-bloated.
Instead of SaaS blue or startup purple, Petsy uses a warm earthy cocoa system: dark cocoa brown text (#3A2315) on creamy ivory (#FAF5EF), warm amber CTAs (#A6633C), soft peach chips and warm taupe metadata. Dark mode inverts gracefully to dark espresso (#1E1B18) and warm charcoal surfaces without losing warmth. Pure black on white would have felt clinical, like a veterinary records system — the earthy palette signals care, nature and premium softness at once. A wood-floored pet hotel, not a fluorescent-lit kennel.
A deliberate dual-font strategy: geometric Poppins for headings, buttons and UI labels; soft rounded Nunito Sans for body, timestamps and captions. Rounded geometry reads friendly; bold headings give confidence without aggression; spacious letterforms feel calm and unhurried. Sharp enterprise fonts (tight Inter, small Roboto) would destroy the emotional warmth — Poppins + Nunito Sans is the opposite choice: premium but playful, readable but warm.
Platform-adaptive, not one-size-fits-all Material. iOS gets BouncingScrollPhysics rubber-band scroll, spring page transitions, BackdropFilter blur on modals, CupertinoAlertDialog, draggable floating bottom sheets and edge swipe-back. Android gets ClampingScrollPhysics, InkWell ripples and Material 3 shared-axis transitions. The architecture is the standard hybrid — Material design system + a platform adaptation layer + Petsy brand customization — so neither platform feels like a port.
A single DashboardWidget hosts 25+ functional areas: Operations (booking requests/records, live kennel occupancy grid, calendar, daily task board), Financials (invoices, categorised expenses, revenue/occupancy reports with CSV export), Clients & Pets (full CRUD with a 3-step onboarding form and 168 breed options), Communication (WebSocket chat, automated reminders), Business Management (staff, services, subscriptions, marketplace) and 12 settings sub-sections covering everything from tax rates to per-table column visibility.


The frontend follows MVVM+ with the Elementary pattern: Model holds pure business logic with no Flutter deps, WidgetModel exposes reactive rxdart streams for UI state, and Widget is pure rendering. Backed by provider for scoped DI, auto_route for typed navigation, dio + retrofit for generated API interfaces, flutter_secure_storage for JWTs in Keychain/Keystore, freezed for immutable models, theme_tailor for type-safe design tokens and shimmer skeletons for every list load.
Python 3.12 on FastAPI with fully async I/O: JWT auth (30-min access, 7-day refresh), ~120 REST endpoints across 22 modules, a WebSocket server for chat, SQLAlchemy async ORM over PostgreSQL via asyncpg, Redis for caching and refresh tokens, and Celery for background reminder jobs. The 22-table schema is fully multi-tenant — every entity carries a business_id so one user can own multiple businesses.
Identity is separated from context. The JWT identifies only the user (sub, email, exp); every request carries an X-Business-ID header, and a get_current_business() dependency validates it against the user's owned businesses — closing the IDOR hole. The Flutter side sets it in a Dio interceptor, so switching businesses is instant with no re-auth. Three auth paths are supported: email + bcrypt password, Google OAuth id_token verification, and an SMTP forgot-password flow.
CRUD stays fast by default on indexed PK lookups and in-memory JWT verification. Expensive paths got surgical fixes: GET /kennels/stats folds 4 COUNT queries into one CASE WHEN aggregate; GET /reports/clients kills an N+1 with joinedload(Client.pets), dropping 501 DB hits to 1. Heavy aggregates (overview, revenue, occupancy) are Redis-cached with business-scoped keys and TTLs from 15 min to 1 hour, invalidated on any booking/invoice write. Redis failure falls back to Postgres — a cache outage never takes the API down.
Client–business messaging runs over WebSocket at /ws/chat/{conversation_id}, with a connection manager broadcasting to all participants and message types for text, image, file and system plus typing indicators and read receipts. A Celery beat scheduler runs daily at 6AM to process reminders — birthdays within 15 days, vaccinations within 30, deworming, and optional repeat/upcoming-booking nudges — each independently configurable per business so a dog's birthday never gets missed.
Beyond the app and backend sits a Next.js webapp: a public marketing site and a set of client-facing micro-flows served over plain URLs — self-onboarding, per-booking consent forms, shareable invoice views (sent over WhatsApp), staff invite acceptance, password resets and print-optimised reports. A pet parent shouldn't install anything to sign a consent form. Next.js API routes act as a Backend-for-Frontend, proxying to FastAPI without exposing credentials, and the landing page carries the exact same earthy palette, type personality and motion as the app.
