Weezdraw était une plateforme de compétitions skill-game payées en Bitcoin : achat de tickets, quiz, roue de la chance, gagnants en direct via Twitch. J'ai porté le projet seul de bout en bout — design, frontend Next.js 15, intégrations Stripe / NextAuth / Socket.IO, instrumentation marketing complète, copy et identité. Le projet a été arrêté courant 2025 ; cette page documente le travail réalisé.
Weezdraw était positionnée comme « the first Bitcoin skill competition platform » : achat de tickets, vérification d'âge, quiz, roue de la chance, gagnants et streaming Twitch intégrés. J'ai conçu, designé et développé le frontend complet en Next.js 15 (App Router), connecté à une API externe via un service HTTP custom et un canal WebSocket Socket.IO, avec Stripe pour les paiements et NextAuth pour l'authentification. Aucune équipe, aucun studio — juste moi, du wireframe au push en production.
App Router avec React 18 et TypeScript strict. Pages buy-tickets, checkout, quiz, profil, FAQ, légal — tout fait main, sans UI lib. Composants lourds (WinnersBanner, FAQ) chargés en dynamic({ ssr: false }) pour préserver le LCP.
Synchronisation des compteurs, du stock de tickets et des prix Bitcoin via Socket.IO. Hooks custom useBitcoinPrice / useDrawBitcoinPrice pour la conversion en direct, montants gérés en bignumber.js pour éviter toute imprécision flottante.
Tunnel d'achat Stripe complet (@stripe/stripe-js), authentification NextAuth 4 avec gestion de session, vérification d'âge obligatoire, code de vérification téléphone. Service HTTP custom (services/Http.ts) pour parler à l'API métier externe.
Front Next.js 15 pur, consommant une API externe. Côté navigateur : Stripe pour le paiement, Socket.IO pour le temps réel, NextAuth pour la session. L'instrumentation marketing (GTM, Klaviyo, TikTok Pixel, Twitter, Trustpilot, CookieConsent) est wrappée en composants React dédiés dans layout.tsx pour rester orchestrable depuis le code.
La pièce maîtresse, c'est le tirage : pour qu'aucun user ne doute, le random vient de Chainlink VRF sur Ethereum mainnet et la cérémonie est diffusée en live Twitch — avec embed direct sur le site. À côté du draw, l'app vit grâce à un prix BTC live propagé par Socket.IO et un hook React unique, calculs en bignumber.js pour ne jamais perdre un satoshi sur un arrondi flottant.
// Source unique pour le prix BTC — propagé par Socket.IO, // fallback HTTP au montage, montants en bignumber.js. export function useBitcoinPrice() { const [price, setPrice] = useState<BigNumber | null>(null); useEffect(() => { // 1. Hydrater immédiatement avec le dernier prix connu (REST). Http.get('/api/btc/price').then((p) => setPrice(new BigNumber(p))); // 2. S'abonner au flux temps réel. const off = socket.on('btc:price', (p) => setPrice(new BigNumber(p))); return off; }, []); return price; } // Dérivé utilisé dans le checkout : combien de sats pour un panier EUR ? export function useDrawBitcoinPrice(eur: BigNumber) { const price = useBitcoinPrice(); if (!price) return null; return eur.dividedBy(price).decimalPlaces(8); }
Pour qu'un utilisateur ne puisse pas se demander si le tirage était « arrangé », le random venait de Chainlink VRF sur Ethereum mainnet. Le contrat appelait le Coordinator, attendait le callback vérifié cryptographiquement, puis le résultat était diffusé en live sur Twitch — avec un embed du stream sur le site pendant le draw. Le hash de la transaction était public : n'importe qui pouvait rouvrir Etherscan et reconstituer le tirage.
Achat de tickets en EUR avec affichage du contre-valeur BTC live, panier persisté entre /buy-tickets et /checkout, modale FirstTicket pour onboarder les nouveaux, modale SoldOut quand l'édition est fermée. Erreurs Stripe mappées vers des messages utilisateur en FR/EN.
Modal AgeVerification servie au premier visit, persistance via cookie HttpOnly. Code de vérification téléphone (modal VerificationCode) avec champ FontAwesome + react-phone-input. CookieConsent câblé à GTM pour bloquer les pixels avant accord.
GTM, Klaviyo, TikTok Pixel, Twitter conversion tracker, Trustpilot, SchemaOrg — chaque provider est un wrapper React dédié, monté dans layout.tsx sous condition de consentement. Tous les events e-commerce (view_item, add_to_cart, purchase) sont émis depuis un dispatcher unique.