← Back to work
Private client project 2025 — 2026·Full-stack Engineer

Buddy Assist

Pet-care services marketplace with bookings and live notifications.

Overview

The project

Buddy is a marketplace where pet owners discover vendors, book veterinary and grooming services, and manage care-plan subscriptions. I built the consumer-facing Nuxt client and worked across the Laravel API and Keycloak SSO that back it, focusing on the booking flow, vendor discovery, and real-time notifications.

Screens

Screenshots

Tap any image to enlarge. Use arrow keys to navigate.

Stack

What I built it with

Nuxt 4Vue 3PiniaTailwind CSSLaravel 11KeycloakPusherMySQL

My role

What I owned

  • Built the consumer web app: pet management, service booking, and care-plan subscriptions.
  • Implemented cookie-based PKCE auth against Keycloak so the SPA never holds raw tokens.
  • Wired real-time booking and notification updates over Pusher/WebSockets.
  • Integrated map-based vendor search and payment-method management.
  • Contributed to the multi-vendor Laravel API powering the platform.

Architecture

How it's wired

  • 01Nuxt 4 SSR client talking to a Laravel 11 multi-vendor REST API.
  • 02Keycloak as the identity provider; backend mediates token exchange and issues HttpOnly session cookies.
  • 03Pusher channels for live booking status and notifications, with a fallback slug set for resilience.
  • 04Geospatial vendor search backed by MySQL spatial columns.

Hard parts

What was challenging

The decisions worth talking about in an interview.

Cookie-based PKCE without exposing tokens

A public SPA can't safely hold a client secret. I ran the OIDC authorization-code flow with PKCE and had the backend exchange the code and set HttpOnly cookies, so the browser never touches raw access tokens — at the cost of carefully allowlisting Keycloak and the WebSocket host in CSP.

Real-time notifications that survive a settings failure

Channel subscriptions depend on dynamic event slugs fetched from the settings API. If that call failed, notifications would silently stop. I merged the dynamic slugs with a hard-coded fallback set via a deduplicating Set so live updates keep working even when settings can't load.