SB
projets
Live · 2026 Personnel

Klabi

PWA invite-only qui remplace un groupe WhatsApp de 60 maîtres de chiens à Vaulx-en-Velin. Centralise les sorties du soir (3 spots fixes + ad-hoc), l'enregistrement de balades GPS en direct et le partage des parcours. Auth JWT avec magic-link, photos sur Cloudflare R2, déploiement free-tier complet.

Le problème

Pourquoi j'ai construit ça

Le groupe WhatsApp du quartier accumule 60 maîtres de chiens, mais l'info utile (qui sort ce soir ? à quel spot ? qui rejoint ?) se perd dans le scroll au milieu des photos et autres messages. Les gens hésitent à relancer le groupe « pour rien », et finissent par sortir seuls alors qu'on aurait pu se croiser. Klabi centralise précisément ces deux usages : se voir le soir et partager les parcours. Trois spots fixes affichent en temps réel qui s'y déplace, un membre peut lancer un appel ailleurs en deux clics, et chacun peut enregistrer sa balade GPS en direct puis la partager comme inspiration pour les autres.

Highlights

Ce qui est intéressant techniquement

01

PWA installable avec enregistrement GPS en arrière-plan

Geolocation API avec watchPosition, Wake Lock API pour empêcher l'écran de s'éteindre pendant la marche, persistance localStorage avec TTL 6h pour reprendre une session interrompue (téléphone fermé, browser killed). Manifest + Service Worker pour l'installation « Ajouter à l'écran d'accueil » sur iOS et Android, le tracé reste fluide même hors-ligne.

02

Storage abstraction R2 ↔ FS via SpEL conditional beans

Interface PhotoStorage avec deux implémentations sélectionnées au boot via `@ConditionalOnExpression("'${klabi.r2.bucket:}'.isEmpty()")` — LocalFs en dev, Cloudflare R2 (S3-compatible, SDK AWS v2 + UrlConnectionHttpClient) en prod. Migration Flyway V25 backfille les avatars existants pour le swap, V26 redirige les photos seedées vers les URLs publiques R2.

03

Spring Boot 3.5 sous le health-check Render free tier

Le tier gratuit Render coupe le déploiement si l'app ne répond pas en 60s. Spring Boot 3.5 + Hibernate + Flyway boot en ~160s à froid : activation de `spring.main.lazy-initialization=true` pour différer la création des beans non-essentiels à la première requête. Combiné à un ping UptimeRobot toutes les 5 min sur `/actuator/health`, le cold-start de 50s disparaît pour les utilisateurs.

04

Auth JWT + magic-link via Brevo, sans Keycloak

Flow passwordless complet : génération d'un token aléatoire (UUID concaténé), hash SHA-256 stocké en DB avec TTL 30 min, email HTML envoyé via Brevo (300/jour gratuit), vérification + délivrance d'un JWT signé HS256. Spring Security configuré en stateless avec un filter JWT custom, CORS strict, endpoints publics whitelistés (auth, invite preview, health).

05

Activity feed + notifications via jsonb Postgres

Table `notifications` avec colonne jsonb pour les payload event-specific, mappée en Hibernate 6.6 via `@JdbcTypeCode(SqlTypes.JSON)`. Le service notification factorise les events (callout lancé, balade partagée, etc.) et l'activity feed du quartier les agrège pour les afficher en chronologique avec liens vers les profils membres et les balades.

06

26 migrations Flyway sans aucune réécriture

De V1 (schéma initial) à V26 (R2 photo URLs), chaque évolution du schéma est une migration versionnée, avec backfill explicite quand nécessaire (V25 strip `/uploads/` des URLs avatar legacy, V23 ajoute `shared_at` sans casser les anciennes balades). Le commentaire en tête de chaque fichier explique le *why* de la migration et pas seulement le *what*.

Stack

Sous le capot

Backend
Java 17 Spring Boot 3.5 Spring Security JWT (JJWT) Spring Data JPA lazy-init
Frontend
React 18 TypeScript Vite Tailwind v4 React Router v7 Leaflet
PWA
Service Worker Web Manifest Geolocation API Wake Lock API localStorage TTL
Persistence
PostgreSQL 17 (Neon) Hibernate 6.6 Flyway (26 migrations) jsonb + @JdbcTypeCode
Storage
Cloudflare R2 (S3 SDK v2) PhotoStorage abstraction @ConditionalOnExpression
Email
Brevo (free 300/day) Magic-link flow HTML email templates
Ops
Render (free tier) Cloudflare Pages UptimeRobot keep-warm Sentry (errors)

Statut actuel

Lancement en cours auprès des 60 voisins maîtres de chiens du groupe WhatsApp d'origine. Beta privée d'abord, ouverture large dans la foulée. Suite envisagée avec la communauté : demande de garde, services entre voisins, recos vétos — toute fonctionnalité qui mérite d'être centralisée plutôt que de se perdre dans le scroll.