SoPup
A Dual-Mode iOS Application for Safe Dog Socialisation
Quick summary
SoPup is a serverless iOS app designed to promote safe dog socialisation. It introduces a dual-mode system (Puppy Mode and Social Mode) to enforce welfare rules and guide responsible interactions.
Timeline: June - August 2025
Role: UX Engineer & Software Engineer (end-to-end: research, design, implementation)
Tools: SwiftUI, Firebase (Auth, Firestore, Cloud Functions, Cloud Messaging, Storage), Node.js/TypeScript, Figma
Want to test the app?

Problem statement
Not all dog-to-dog interactions are safe. Veterinary and behavioural research shows that compatibility depends on factors like play style, sex pairing, neuter status, and age. Yet most existing dog social apps ignore these welfare rules, creating risks for puppies and anxious dogs.
Goals & Scope
Create a dual-mode iOS platform that adapts to age and vaccination status.
Dual Mode iOS platform
Prioritise nearby options via Swift Core Location
Provide location aware discovery
Design a research-informed matchmaking algorithm (behaviour, neuter status, age, location)
Develop a score & sort matchmaking algorithm
Require mutual approval before opening real-time chat (with push notifications)
secure, consent based chat
Safety by design: enforce health advisories, disable meet-ups for puppy mode user
Enforce safety in Puppy Mode
Demonstrate a serverless architecture that runs such as matchmaking, chat, meet up features at scale with low maintenance
serverless Firebase architecture
Research & Insights
From this research phase, three key outcomes shaped SoPup’s design:
Competitive Review:
Existing apps like Pawmates and DogPack offer polished UIs and event features, but none address behavioral or health-based matchmaking, leaving a clear innovation gap.
User Survey:
Dog owners value clear profiles, effective filters, and secure chat before meeting. They also requested extra filters (weight/size) and post-meet-up reviews to improve trust.
Requirements Defined
By combining market gaps with direct user feedback, I established the functional and non-functional requirements for SoPup. This included dual-mode safety (Puppy vs Social), compatibility filtering, and enforced communication safeguards.
From Research to Algorithm
The research insights became the backbone of SoPup’s matchmaking logic.
-
Market analysis revealed the gap in behavioural and health-based filtering.
-
User surveys confirmed the need for clear profiles, effective filters, and secure chat before meeting.
-
Requirements gathering prioritised a dual-mode safety system to protect unvaccinated puppies.
These findings translated into a score-and-sort algorithm that applies veterinary and behavioural rules directly into the technology. Instead of leaving safety to user discretion, SoPup’s system enforces it by design.
On the client side
User preferences (such as age, neuter status, play style, and distance) are stored persistently with SwiftData, ensuring filters are saved locally and remain available offline. When a match request is made, these filters are packaged into a request object and sent to the backend.

Match filters stored with SwiftData and sent to the backend for scoring
On the Backend
A Firebase Cloud Function processes this request. It first removes excluded candidates and applies hard filters (e.g., age, gender, neuter-only rules). Remaining candidates are then scored in two stages: a compatibility score that measures behavioural alignment (play style, neuter compatibility, health, environment), and a location score that weights proximity using GPS data. These scores are combined into a total match score, and candidates are sorted and returned to the client in real time.

Cloud Function log output showing compatibility and location scores calculated per candidate before ranking
Features
SoPup introduces a dual-mode system:
Puppy Mode (≤12 weeks)

Social Mode (12+ weeks)

For dogs under 12 weeks, meet-ups are disabled and vaccination status is tracked. This ensures safety by design, enforcing welfare rules automatically.
For vaccinated dogs, the app enables meet-ups, and reviews.
Disable Features on Puppy mode

Meet up Alert
Disable meet up tab
Meet-up Flow
SoPup’s meet-up flow is designed around consent, trust, and safety:
-
Mutual approval required: Owners must both accept a match before chat is enabled.
-
Secure chat first: Conversations happen in-app, ensuring owners can connect safely before meeting.
-
Playdate scheduling: Once matched, owners can propose dates, times, and locations for meet-ups directly in the app.
-
Trust-building reviews: After a meet-up, owners are prompted to leave feedback, reinforcing accountability and transparency in the community.

Match Request
Chat
Meet Up Request
Review
📌 Impact: This flow ensures that every step from first match to real-world playdate is structured to build safety and trust between owners.
Mode Switcher
To ensure vaccination safety is enforced, SoPup includes a Mode Switcher feature:
-
Owners enter the dates of their dog’s vaccinations.
-
A Cloud Function verifies the data; once both doses are valid, the UI automatically updates.
-
The dog’s profile can then transition from Puppy Mode to Social Mode, unlocking behavioural fields (play style, environment, neuter status) and enabling full matchmaking.
📌 Impact: This ensures that only fully vaccinated dogs can join Social Mode, embedding veterinary guidance into the system logic and preventing unsafe meet-ups by default.

Implementation
The implementation phase turned SoPup’s design into a working iOS prototype built on a three-layer architecture: SwiftUI mobile client, iOS frameworks, and a Firebase serverless backend. This setup delivers real-time data, scalability, and safety-by-design enforcement.

The app supports authentication, matchmaking, chat, meet-ups, and reviews, with data flowing seamlessly between the iOS frontend and the Firebase backend. The implementation focused on both functional requirements (dual-mode system, compatibility scoring, safe communication) and non-functional requirements (scalability, maintainability, cost efficiency).
📌 Impact: This ensures that only fully vaccinated dogs can join Social Mode, embedding veterinary guidance into the system logic and preventing unsafe meet-ups by default.
Frontend (iOS App – SwiftUI)
The iOS client was built with SwiftUI using the MVVM design pattern for maintainability and clean separation of UI and logic.
-
SwiftData stores user filters locally for persistence and offline use.
-
Core Location provides GPS-based proximity data for matchmaking and meet-up scheduling.
-
The frontend integrates directly with Firebase SDKs (Auth, Firestore, Messaging, Storage) for real-time updates.
Backend (Firebase Cloud Functions – Node.js/TypeScript)
The backend runs on Firebase Cloud Functions (2nd Gen), deployed to Google Cloud Run for auto-scaling.
-
Encapsulates business logic for matchmaking, chat creation, meet-ups, reviews, and mode switching.
-
Organised into controllers, services, and repositories for separation of concerns.
-
Enforces safety rules such as blocking meet-ups in Puppy Mode and validating vaccination dates before mode switching.
Data Layer (Firestore & Storage)
The backend runs on Firebase Cloud Functions (2nd Gen), deployed to Google Cloud Run for auto-scaling.
-
Firestore stores structured data (profiles, matches, messages, meet-ups, reviews) with real-time listeners that instantly update the client.
-
Firebase Storage hosts profile and dog images.
-
Cloud Messaging (FCM) delivers push notifications for matches, messages, and meet-up requests.
📌 Impact: This serverless approach ensures low maintenance, elastic scaling, and safety by design, with welfare rules embedded in backend logic rather than left to user choice.
Together, these three layers form the foundation of SoPup’s architecture. To illustrate how they interact in practice, the following data flow shows how information moves across the system during authentication, matchmaking, and real-time interaction.
Data Flow
The SoPup system manages data interactions seamlessly across the mobile client, iOS frameworks, and Firebase backend.
-
Authentication: Firebase Auth verifies the user and retrieves their profile and dog data from Firestore.
-
Mode Switching: Vaccination dates are stored in Firestore; Cloud Functions validate readiness and update the profile with a Social Mode flag.
-
Matchmaking: User filters (saved in SwiftData) are packaged into a scoring request. Cloud Functions apply exclusions, filters, and compatibility scoring before returning a ranked list of dogs.
-
Chat & Notifications: Accepted matches trigger chat room creation in Firestore. Cloud Messaging (FCM) delivers push notifications for new matches, messages, and meet-up requests.
-
Meet-ups & Reviews: Meet-up details are stored in Firestore with automatic status updates. After completion, review functionality is unlocked and stored alongside the dog’s profile.
📌 This flow ensures that safety and compatibility rules are enforced automatically, while real-time listeners keep the client updated without manual refresh.
Main Features Implemented
This section highlights the key components built for SoPup.
Each example shows how user-facing functionality ties to backend logic and system requirements.
🔐 Authentication & Profile Creation
-
Auth: Implemented email/password + Apple Sign-In using Firebase Auth. Tokens validated server-side before any Cloud Function calls.
-
Onboarding: Multi-step flow that creates both User + Dog documents in Firestore in a single transaction, uploads photos, generates a geohash for location queries, and stores the FCM token for push notifications.
-
Safety by design: DOB auto-classifies Puppy vs. Social Mode, gating meet-ups until vaccination is complete.

Apple Sign-In button + onboarding flow
code snippet: handleAppleSignIn() nonce → SHA-256 → Firebase credential.
🎯 Matchmaking & Scoring
-
Algorithmic scoring: Ranked candidates using a score-and-sort pipeline that combines distance, compatibility, and behavioural filters.
-
Client–server bridge: Filters (SwiftData) persisted locally and packaged into a matchScoringDTO sent to the backend. A Cloud Function applied exclusions, hard filters (e.g. neuter-only), and compatibility scoring, then returned a ranked list.
-
UI integration: MatchingViewModel.applyScoring() orchestrates candidate IDs, user location, and exclusions, then updates matchedProfiles to drive the card-based UI.

match filters + scored match cards
code snippet: applyScoring() method, builds DTO, calls backend, applies ranked results to the UI.
📅 Meet-ups & Reviews
-
What it does: From any chat, owners can propose a time & place, accept/reject/cancel, mark the meet-up as Completed, and then leave a review.
-
How it works:
-
MeetupViewModel.createMeetupRequest(...) builds the payload (chatRoomId, time, location, receiver IDs) and calls a Cloud Function via MeetupService; Firestore stores the request and FCM notifies the recipient.
-
MapKit powers the location picker: search with MKLocalSearch (POIs) or choose current location via MKMapItem.
-
After the playdate, the owner manually taps “Completed.” The backend validates membership and updates status; this unlocks the review prompt in the UI.
-
-
Safety by design: Meet-ups are only available after mutual Match Request approval and are disabled in Puppy Mode by server rules.

Create meetup from a chat screen
code snippet: createMeetup() method, collects time/place with MapKit, builds a request, and sends it to backend via MeetupViewModel.
📌 More Features
In addition to the highlighted flows, SoPup includes other core features that complete the end-to-end experience:
Owners can send, accept, reject, or cancel requests. Accepted requests automatically open a chat room.
📩 Match Requests
Vaccination dates are tracked in the backend. Dogs can only switch from Puppy Mode to Social Mode when requirements are validated.
🔄 Mode Switcher
Real-time messaging powered by Firestore listeners, with support for sending meet-up requests directly from chat.
💬 Chat
Profiles are enriched with behavioural tags, vaccination data, and aggregated reviews, providing a transparent view before meeting.
👤 Profile
After meet-ups, users can rate and review each other. Average ratings are displayed on profiles to build trust.
⭐ Reviews
🔗 For full implementations, see the
Challenges & Solutions
During implementation and TestFlight testing, several technical challenges surfaced. These highlight how engineering trade-offs and debugging shaped the final product:
1. ISO-8601 Parsing on iOS 18
Problem: Some devices showed “No matches found” despite valid backend responses.
Cause: iOS 18’s stricter timestamp handling broke JSON decoding.
Solution: Centralised JSON parsing and introduced a custom decoder that supports fractional seconds.
Impact: Fixed cross-device compatibility, preventing silent data loss.


2. Chat Crash After Match Acceptance
Problem: The app sometimes crashed when returning to the chat list.
Cause: Concurrent mutations in dog/user caches triggered a data race during list assembly.
Solution: Wrapped caches in a Swift actor and enforced main-thread sorting.
Impact: Eliminated crashes in Build 5; chat became stable across TestFlight sessions.
3. Location Matching Strategy
Problem: Tried geohash indexing for spatial queries in Firestore, but queries became overly complex.
Solution: Switched to the Haversine formula for reliable distance scoring.
Impact: Simplified implementation, ensured correctness, and reduced development risk.
Testing & Validation
Test Strategy
End-to-end flows
(Auth, Onboarding, Matchmaking, Chat, Meet-ups, Reviews, Mode Switcher)
Black-Box
Verified client and backend with Postman + Cloud Logs.
White-Box
10 TestFlight users, unguided tasks across devices/iOS versions.
Usability
Key Fixes
🗓 Date Parsing: Unified ISO-8601 handling → fixed empty matches on iOS 18.
💬 Chat Crashes: Added Swift actor for caches → stable chat list.
📍 Location Matching: Swapped geohash for Haversine formula → simpler & reliable.
Outstanding Bugs (Build 5)
-
Home refresh anomaly: sometimes no matches despite backend valid.
-
Mode Switcher disabled on one device.
-
UX polish: duplicate requests/reviews show generic errors.
📌 Result: Stable end-to-end operation, essential functional and requirements, and core non-functional requirements achieved. Remaining issues logged for iteration.
Future Work & Improvements
While SoPup achieved its core requirements, several enhancements could expand its value:
✨ Features
-
Multiple Dogs per User: Allow owners to register and manage more than one dog profile.
-
Education Hub: Structured training modules to guide socialisation, with progress tracking. focusing on the puppy mode user.
-
Rich Chat: Support for images, videos, and voice messages for better interaction.
-
Dark Mode: Improve accessibility and personalisation.
⚡ Optimisation & Safety
-
Error Handling: Friendlier error messages for duplicate requests, invalid meet-ups, or reviews.
-
Content Moderation & Admin Tools: Reporting system for users, admin dashboard to review flags, and safeguards against inappropriate content.
💡 Takeaway
This project allowed me to combine UX research, mobile engineering (SwiftUI, SwiftData, MapKit), and serverless backend development (Firebase, Cloud Functions, Firestore) into a single end-to-end product. It reflects my ability to design, implement, and test full-stack mobile systems and, most importantly, to translate complex requirements into a reliable, user-friendly app.

Thank you!