Aller au contenu principal
Mission FreelanceEn productionDuo avec le fondateur
OpenUp logo

OpenUp

Générateur de deep links, live sur openup.to

Un lien partagé sur Instagram ouvre l'app Spotify, Amazon ou YouTube, au lieu d'une WebView où l'utilisateur n'est connecté à rien. 57 applications résolues, 11 in-app browsers contournés. Plusieurs milliers d'utilisateurs, 10 à 15% convertis en payant. Développé from scratch en duo avec le fondateur : Clean Architecture + DDD, edge <50ms via Cloudflare Worker, mobile natif via Capacitor.

57

Apps ouvertes en natif

Spotify · Amazon · YouTube · Uber…

10-15%

Conversion payante

Sur plusieurs milliers d'utilisateurs

11

In-app browsers contournés

Instagram · TikTok · WeChat…

<50ms

Edge Cloudflare

Partout dans le monde

+940 fichiers TypeScript · +190 fichiers domain/application · 8 packages monorepo · 4 plans Stripe EUR + USD · iOS · Android · PWA

Contexte

La mission

Problématique

Les créateurs, marques et entreprises jonglent avec 3 abonnements séparés (Bitly pour shortlinks, Linktree pour la page bio, Beacons pour les QR codes) sans analytics unifié. Le client voulait un seul outil cohérent, premium côté UX et capable de passer à l'échelle internationale dès le jour 1.

Mon rôle

Toute la technique, from scratch, en duo avec le fondateur, en quelques semaines. Architecture, backend Hono DDD, app mobile Capacitor (iOS + Android + PWA depuis une seule codebase), Cloudflare Worker pour les redirections edge et les deep links, intégration Stripe multi-devise, BetterAuth, Cloudflare for SaaS pour les domaines custom, CI/CD Fastlane pour les releases mobiles.

Collaboration

Duo direct avec le fondateur : itérations courtes, décisions produit prises à deux, design system construit en chemin sur shadcn/ui + Tailwind 4. Le site marketing openup.to est sur Framer (hors monorepo), proxifié via le worker pour garder un domaine unique : openup.to (Framer) + app.openup.to (PWA) + openup.to/xxx (redirections edge).

Approche technique

Monorepo basé sur CleanStack (mon template open-source) : Clean Architecture + DDD, type-safety bout-en-bout via Hono RPC. Les redirections shortlinks vivent sur l'edge Cloudflare pour rester sub-50ms partout. iOS et Android compilent depuis le même code que la PWA grâce à Capacitor.

Aperçu

Captures de l'application

Captures réelles de la version live, prises sur app.openup.to.

Fonctionnalités

5 piliers, un seul outil

Tout ce que les créateurs, marques et entreprises veulent dans un outil de gestion de liens, sans les compromis. Bilingue FR/EN.

Deep links natifs

57 applications résolues : un lien Spotify ouvre le bon titre dans l'app, un lien Amazon la bonne fiche produit. Intent Android avec fallback navigateur, Universal Links iOS.

Liens raccourcis

URLs courtes openup.to/xxx avec slug custom, expiration, limite de clics, filtre géo, mot de passe, UTM et scheduling.

QR Codes dynamiques

8 motifs, repères Pro, logo (auto-détecté plateforme ou custom image), palette + couleurs custom. Export PNG/JPG/SVG, ajout Apple Wallet en 1 tap.

Link-in-bio WYSIWYG

Éditeur avec preview iPhone temps réel. Widgets audio, Google Maps, contact chat, Calendly, Spotify. Thèmes, dark mode, drag & drop.

Analytics complet

Dashboard liens + QR + bio. KPIs, évolution temporelle, répartition appareil/OS/navigateur/géo/heures, top sources de trafic.

Domaine personnalisé

Branding total via Cloudflare for SaaS. Configuration DNS guidée, vérification automatique, certificats SSL provisionnés à la volée.

Sortir des in-app browsers

11 navigateurs intégrés détectés server-side. Scheme d'évasion pour Instagram et Facebook, instructions guidées pour TikTok et WeChat qui n'en laissent aucun. Cascade de secours sur 5 navigateurs iOS, détection d'ouverture réelle via visibilitychange, repli web à 1,8s.

Multi-devise EUR + USD

Détection auto de la devise via geo IP, override possible. Stripe gère un Product avec un Price par couple devise/période. Promos appliquées sur les 2 devises automatiquement.

Mobile natif iOS + Android

Capacitor partage 100% du code avec la PWA web. Wrappers natifs pour clipboard, share, haptics. Releases via Fastlane vers TestFlight + Play Store automatiques sur tag.

Architecture

Pensée pour la prod, pas pour le démo

Chaque couche isolée et testable. Chaque décision technique justifiée par un besoin produit, pas par la mode.

Clean Architecture + DDD

Zéro import externe dans le domaine (ddd-kit + Zod uniquement). Result<T,E>, Option<T>, ValueObjects, Aggregates avec events. Use cases purs : zéro logique métier, tout dans les agrégats.

Edge <50ms partout

Cloudflare Worker dédié pour les endpoints critiques : redirections courtes openup.to/xxx et proxy Framer du site marketing. Latence sub-50ms partout dans le monde, scaling auto, coût négligeable.

Event-driven découplé

Domain events après chaque mutation persistée. Handlers idempotents pour les side effects (emails, logs, notifs). Zéro appel direct à un service externe depuis un use case.

Stack technique

Technologies utilisées

Hono
TypeScript 5
Drizzle ORM
PostgreSQL
Cloudflare Workers
Cloudflare for SaaS
Capacitor
React 19
Vite + PWA
TanStack Router
TanStack Query
Hono RPC client
BetterAuth
Stripe
Resend
Cloudflare R2
Apple Wallet
Google Wallet
shadcn/ui
Tailwind 4
i18next
Zod
inwire DI
Clean Architecture
DDD
Fastlane CI/CD

Monorepo · 8 packages

apps/apiBackend Hono (DDD, 9 modules domaine)
apps/appMobile Capacitor + PWA (TanStack Router, Hono RPC)
apps/link-routerCloudflare Worker (redirections + proxy Framer)
packages/ddd-kitResult, Option, Entity, ValueObject, EventDispatcher
packages/drizzleSchema DB + migrations + seeds
packages/reserved-slugsSlugs interdits partagés API + worker
packages/uishadcn/ui partagé Tailwind 4
packages/testUtilitaires de test (mocks, factories)

Questions fréquentes sur ce projet

Les questions que mes clients m'ont posées sur cette mission.

Pourquoi un Cloudflare Worker pour les redirections plutôt qu'une route API classique ?

Une redirection shortlink doit être instantanée partout dans le monde. Le worker tourne sur l'edge Cloudflare (latence sub-50ms en Tokyo comme à Paris), scale tout seul, coûte une fraction d'un serveur classique, et sert aussi de proxy au site marketing Framer pour garder un seul domaine.

Hono plutôt que Next.js ou Fastify pour l'API, pourquoi ce choix ?

Hono est minuscule, runtime-agnostic (Node, Bun, Workers, Deno) et embarque un client RPC type-safe natif (hc<AppType>) qui garantit le contrat API par les types entre l'API et le frontend. C'est exactement ce qu'il faut pour une archi DDD/CQRS où on veut zéro framework dans le domaine.

Les deep links, ça marche vraiment ou c'est juste du fallback web ?

Vraiment, et c'est le cœur du produit. Un résolveur couvre 57 applications de destination : un lien Spotify ouvre le bon titre dans l'app Spotify, un lien Amazon la bonne fiche produit. Côté iOS on passe par les Universal Links, côté Android par un intent:// avec browser_fallback_url. Il n'y a pas de scheme custom openup:// : l'app OpenUp elle-même s'ouvre via Universal Links et App Links vérifiés.

Comment tu sors un lien du navigateur intégré d'Instagram ou de TikTok ?

11 navigateurs intégrés sont détectés côté serveur à partir du user-agent, avec une stratégie par application. Instagram et Facebook exposent un scheme d'évasion, on l'utilise pour forcer l'ouverture dans le navigateur système. TikTok, WeChat, LINE et Twitter n'en laissent aucun : la seule réponse honnête est une page d'instructions localisée qui pointe le menu au bon endroit selon l'app. Partout ailleurs, un interstitiel tente le deep link natif avec une cascade de secours sur cinq navigateurs iOS. On sait si ça a marché en écoutant visibilitychange, blur et pagehide : si la page passe en arrière-plan avant 1,8s, l'app a pris la main et on annule le repli web.

Capacitor pour mobile, pas React Native, c'est pas moins natif ?

Capacitor partage 100% du code avec la PWA web. Le résultat est packagé en vraie app iOS et Android publiée sur TestFlight et le Play Store via Fastlane CI. On garde l'accès aux APIs natives (clipboard, share, haptics, deep links iOS/Android) via des wrappers, et on évite d'entretenir une troisième codebase. Pour un SaaS dont la valeur est dans la logique métier, pas dans des écrans 100% natifs, c'est le bon trade-off.

Multi-devise EUR/USD et Apple Wallet, c'était dans le scope initial ?

Non, deux ajouts incrémentaux après le MVP. Multi-devise pour ouvrir hors zone euro (détection auto via geo IP + override possible, Stripe gère un Product avec un Price par devise). Apple Wallet pour le use case retail/event : carte avec QR scannable directement depuis le wallet, ajouté en 1 tap depuis l'app. Possible parce que l'archi DDD permettait d'ajouter sans toucher au reste.