J'ai co-fondé Global Pet Sitter avec mon ami Geert. Deux développeurs, plus de 10 ans d'expérience en housesitting à nous deux, qui essaient de construire quelque chose de transparent et communautaire. Ça a commencé comme une idée simple et honnêtement, c'est devenu l'une des expériences les plus éducatives de ma vie
Pourquoi on l'a créé
On était nous-mêmes housesitters depuis des années. On utilisait des plateformes comme TrustedHousesitters et Nomador. Et honnêtement, on en avait marre
Les problèmes s'accumulaient :
- des frais qui déraillent - TrustedHousesitters a introduit des frais de réservation de 12$ par sit en plus de l'abonnement annuel. On avait l'impression de se faire gratter jusqu'au dernier centime
- un support client qui ne répond pas - les emails restent sans réponse, le support téléphonique supprimé, juste des chatbots. Quand quelque chose tourne mal pendant un sit, tu es livré à toi-même
- un système d'avis qui semble cassé - les faux avis ne peuvent pas être supprimés même avec des preuves. Aucune responsabilité quand les hôtes ou sitters se comportent mal
- pas de vraie vérification - les vérifications de fond sont volontaires et payées par le sitter. La plateforme agit à peine même quand un vol ou une négligence d'animal est signalé
On lisait les mêmes plaintes encore et encore sur Trustpilot et Sitejabber. TrustedHousesitters a une note de 2.7/5 sur Sitejabber avec plus de 1000 avis. Des gens décrivant des vols, des dégâts matériels, des annulations de dernière minute, et une plateforme qui "a enquêté mais a refusé d'agir"
Quelque chose qui avait commencé comme centré sur la communauté est devenu sur-commercialisé. Et on s'est dit, peut-être qu'on pourrait faire mieux
La mission était claire : construire quelque chose de transparent où propriétaires d'animaux et sitters pourraient se connecter sans toutes ces frictions. Ça semble simple non ? Haha
La stack technique
On est partis sur Next.js 16 (App Router + Turbopack), Convex pour le backend temps réel, et Clerk pour l'auth. Tailwind pour le style parce que la vie est trop courte pour écrire du CSS from scratch
Pourquoi Convex ? Des mises à jour en temps réel out of the box. Quand un sitter postule ou qu'un message arrive, tu le vois instantanément. Pas de setup websocket, pas de polling, pas de prise de tête. Le schéma est défini en TypeScript, les requêtes sont type-safe, et les déploiements marchent tout simplement
// voilà à quel point les requêtes Convex sont propresExport const getApplicationsByAssignment = query({args: { assignmentId: v.id("sitAssignments") },handler: async (ctx, args) => {const applications = await ctx.db.query("applications").withIndex("by_sit_assignment", (q) =>q.eq("sitAssignmentId", args.assignmentId)).filter((q) => q.eq(q.field("deletedAt"), undefined)).collect();return applications;},});
La confiance, c'est tout
Quand tu demandes à quelqu'un de s'occuper de son animal, tu demandes beaucoup de confiance. Les animaux, c'est la famille. Les gens ne confient pas leur chien à un inconnu sur internet comme ça
On a passé bien plus de temps sur la vérification, les avis et les fonctionnalités de sécurité que prévu initialement. Les contrôles de confidentialité sont devenus un gros sujet. Et honnêtement on aurait dû commencer par là. Construire la confiance, ce n'est pas une fonctionnalité qu'on ajoute après coup, c'est la fondation
Avis en aveugle
Un truc qu'on a construit et dont je suis plutôt content : les avis en aveugle. Les deux parties soumettent leur avis indépendamment, et aucune ne peut voir l'avis de l'autre tant que les deux n'ont pas été soumis (ou que 14 jours se sont écoulés). Ça empêche les avis de représailles et garde les choses honnêtes
Const isReviewVisible = (review: { visibleAt?: number }): boolean => {if (!review.visibleAt) return false;return review.visibleAt <= Date.now();};
Une logique simple mais qui change toute la dynamique
Importer des avis d'autres plateformes
Un problème que les nouvelles plateformes rencontrent : les sitters expérimentés ont déjà des avis sur d'autres sites. Ils ne veulent pas repartir de zéro. Alors on a construit un système d'import d'avis
Le flux fonctionne comme ça :
- L'utilisateur lie son profil sur une autre plateforme (TrustedHousesitters, Nomador, etc.)
- On vérifie qu'il possède bien le profil en lui demandant d'ajouter un code unique à sa bio
- Une fois vérifié, il peut uploader des captures d'écran de ses avis
- GPT-4 Vision extrait automatiquement les données de l'avis
Export const extractReviewFromScreenshot = action({args: { imageUrl: v.string() },handler: async (_, args) => {const response = await openai.chat.completions.create({model: VISION_MODEL,messages: [{role: "user",content: [{ type: "text", text: "Extract the review information:" },{ type: "image_url", image_url: { url: args.imageUrl } },],}],response_format: { type: "json_object" },});// returns: reviewerName, reviewText, overallRating, reviewDate},});
La partie vérification était intéressante. On génère un code unique comme gps-verify-abc123, l'utilisateur l'ajoute à la bio de son profil, et on récupère la page pour vérifier si le code est présent
Const codeFound = html.includes(profile.verificationCode);If (codeFound) {await updateProfileStatus({ status: "verified" });}
Simple mais efficace. Ça empêche les gens de revendiquer des avis qui ne sont pas les leurs
Les marketplaces bifaces, c'est dur
Tu as besoin de propriétaires d'animaux ET de pet sitters. Mais les propriétaires ne rejoignent pas sans sitters, et les sitters ne rejoignent pas sans propriétaires. Le classique problème de la poule et l'œuf
On a fini par se concentrer sur des fonctionnalités qui aident vraiment les deux côtés - la recherche par carte pour trouver des sits près de chez toi, les comptes doubles pour être à la fois sitter et propriétaire. Les petits détails qui rendent l'expérience plus fluide
Le problème de la recherche par carte
La recherche par carte semble facile jusqu'à ce que tu la construises vraiment. On utilise LocationIQ pour le géocodage (bien moins cher que Google) et on a dû construire un système de backfill pour les utilisateurs existants
Export const backfillSitterCoordinates = action({args: {batchSize: v.optional(v.number()),delayMs: v.optional(v.number()), // rate limit protection},handler: async (ctx, args) => {const sitters = await ctx.runQuery(internal.geocoding.getSittersNeedingGeocoding,{ limit: batchSize });// process in batches to avoid rate limitsfor (const sitter of sitters) {// geocode and update...await new Promise(resolve => setTimeout(resolve, delayMs));}},});
On utilise aussi supercluster pour regrouper les marqueurs quand tu dézoomes. Sinon la carte devient inutilisable avec trop d'épingles
Écouter change tout
Une des plus grandes leçons : écoute tes utilisateurs. On a récemment changé toute notre façon de parler de la plateforme suite aux retours. La façon dont on décrivait Global Pet Sitter ne parlait pas aux gens, alors on a tout réécrit
Chaque plainte est une demande de fonctionnalité déguisée. Chaque utilisateur perdu te montre où ton produit pèche. Plutôt cool quand tu commences à le voir comme ça
Soft deletes partout
On a appris tôt : ne supprime jamais vraiment les données. Tout utilise des soft deletes avec un champ deletedAt. Quand quelque chose tourne mal (et ça arrivera), tu peux récupérer. Quand les utilisateurs demandent "qu'est-ce qui est arrivé à mon annonce ?", tu peux vraiment leur répondre
.filter((q) => q.eq(q.field("deletedAt"), undefined))
Tu vois ce pattern partout dans notre codebase. Un peu pénible à retenir mais ça t'évite tellement de maux de tête
Ce qu'on a livré
En regardant ce qu'on a construit :
- recherche par carte - trouve des sits dans ta zone visuellement avec regroupement de marqueurs
- comptes doubles - sois sitter et propriétaire avec le même profil
- contrôles de confidentialité - tu décides quelles infos partager
- messagerie temps réel - pas besoin de rafraîchir, les messages apparaissent tout simplement
- avis en aveugle - des retours honnêtes sans peur de représailles
- import d'avis - ramène ta réputation d'autres plateformes grâce à l'extraction IA
- récompenses early adopter - parce que les premiers utilisateurs ont pris un risque sur nous
Et on travaille sur une app iPhone. Elle arrive :)
La technique n'était pas le plus dur
J'ai passé tellement de temps à m'inquiéter de la stack technique, de l'architecture, de la performance. Au final, le plus dur c'était de faire en sorte que les gens s'intéressent à ton produit
Le meilleur code du monde ne sert à rien si personne ne l'utilise. J'aurais aimé apprendre ça plus tôt
Cela dit, choisir les bons outils (Convex, Clerk, Next.js) a rendu l'expérience de dev assez fluide pour qu'on puisse se concentrer sur le produit au lieu de se battre avec l'infrastructure
Est-ce que je le referais
Absolument. Même avec toutes les nuits blanches et les moments de doute. Construire quelque chose from scratch avec quelqu'un en qui tu as confiance t'apprend des choses que tu ne peux pas apprendre autrement
C'est peut-être ça la vraie leçon. Le produit peut réussir ou échouer, mais tu en sors toujours en sachant plus qu'au départ
Stay Updated
Get notified about new posts on automation, productivity tips, indie hacking, and web3.
No spam, ever. Unsubscribe anytime.



