DIGGR — Ce qu'on a fait .

Récap de l'implémentation du système référral / airdrop DIGGR basé sur tes specs. Tout est en ligne sur diggr.bot et marche déjà à 90%. Il reste juste à brancher les clés X OAuth depuis le Developer Portal.

Sommaire

  1. Ce qui marche déjà
  2. Ce qu'il te reste à faire (15 min)
  3. Le flow utilisateur final
  4. Le flow admin (panneau /admin)
  5. Stack technique & archi
  6. Vérification des tâches X — détails
  7. Comment marche le référral
  8. Bot Telegram — statut
  9. Coût actuel et future bascule payante

1. Ce qui marche déjà en ligne

2. Ce qu'il te reste à faire 15 min

Important : j'ai mis des placeholders pour X_CLIENT_ID et X_CLIENT_SECRET dans Cloudflare parce qu'on n'avait pas encore créé l'app sur le Developer Portal X. Il faut donc faire ça maintenant pour que le login X fonctionne.

Étape 1 — Créer l'app sur X Developer Portal

  1. 1Va sur developer.x.com avec le compte X officiel @diggr_app (ou celui qu'on utilise)
  2. 2Souscris au tier Free (pas besoin de carte bancaire)
  3. 3Crée un Project + une App à l'intérieur (type "Web App, Automated App or Bot")
  4. 4Dans User authentication settings :
    • Active OAuth 2.0
    • Type of App : Confidential client
    • Callback URI : https://diggr.bot/api/auth/x/callback
    • Website URL : https://diggr.bot
  5. 5Récupère le Client ID et le Client Secret (⚠️ le secret n'est affiché qu'une fois)

Étape 2 — Coller les clés dans Cloudflare

  1. 1Va sur dash.cloudflare.com → Workers & Pages → projet diggr-app
  2. 2Settings → Environment variables → Production
  3. 3Édite la variable X_CLIENT_ID : remplace PLACEHOLDER_TO_BE_SET par le vrai Client ID
  4. 4Édite la variable X_CLIENT_SECRET : remplace par le vrai Client Secret (laisse "encrypted")
  5. 5Save
  6. 6Déclenche un re-deploy : sur le dashboard du projet → onglet "Deployments" → bouton "Retry deployment" sur la dernière prod

Étape 3 — Te déclarer admin

Pour que tu puisses accéder au /admin, tu dois te marquer is_admin = true dans la DB. Comme on n'a pas encore d'UI pour ça (poule/œuf), il faut une requête SQL une seule fois dans Supabase Studio :

-- D'abord, connecte-toi sur diggr.bot via X + wallet (pour avoir une ligne dans users)
-- Ensuite, dans Supabase Studio → SQL Editor :

update public.users
set is_admin = true
where x_username = 'ton_handle_x';   -- ou where wallet = 'ton_wallet_solana'

-- Pareil pour ton pote :
update public.users
set is_admin = true
where x_username = 'son_handle_x';

Une fois fait, allez sur https://diggr.bot/admin et vous aurez accès au panneau complet.

Étape 4 — Remplacer le pinned post placeholder

Il y a un pinned post par défaut avec l'ID 0000000000000000000 (placeholder). Quand tu auras posté le vrai tweet pinned, va dans /admin → onglet Posts → "Add a new task post" :

L'ancien placeholder sera automatiquement désactivé (max 1 pinned actif).

3. Le flow utilisateur final

Étape 1 — Connect X

Sur diggr.bot, l'user clique sur "𝕏 Connect X". On le redirige vers X OAuth, il autorise, on récupère son x_user_id + username + followers_count. On crée son compte en DB avec un slug référral unique. JWT cookie posé.

Étape 2 — Connect Wallet

L'user clique "Connect wallet" → modal Phantom/Solflare → signe un message SIWS (gratuit, pas de transaction). Le wallet est lié à son compte X existant. À partir de là il est "qualifié" pour l'airdrop.

Étape 3 — Tasks d'engagement

Sur la section "Engagement Tasks" il voit :

Chaque post affiche 3 actions :

ActionVérification
LikeHonor system → marqué "Pending review" → admin valide en batch dans le panel
RetweetL'user colle l'URL de son RT/quote → on appelle publish.twitter.com/oembed → si author_name === user.x_username ET le tweet référence l'original → auto-vérifié
CommentPareil : URL de son reply, oEmbed vérifie l'auteur

Si oEmbed n'arrive pas à confirmer (tweet supprimé, profile privé, etc.) → fallback en revue manuelle.

Étape 4 — Référral

L'user a un lien https://diggr.bot/r/abc12xyz. Quand quelqu'un clique :

  1. Cookie ref=abc12xyz posé pour 30 jours
  2. Le visiteur fait X + wallet + pinned post terminé → ouvre droit au reward
  3. Le parrain reçoit automatiquement +50 pts via trigger Postgres
  4. Le compteur active_referrals du parrain s'incrémente

Un user ne peut être référé qu'une seule fois (contrainte DB UNIQUE).

4. Le flow admin (panneau /admin)

Onglet "Posts"

Tu peux :

Onglet "Submissions"

La file des soumissions à valider. Tu filtres par statut :

Pour chaque entrée tu vois : @handle X de l'user, type d'action, URL fournie comme preuve, URL du tweet original. Boutons : ✓ Verify ou ✕ Reject.

Quand tu valides : points créditer automatiquement à l'user + ligne ajoutée à points_log (audit) + check du référral reward déclenché.

Onglet "Users"

Recherche par handle X, wallet ou slug. Pour chaque user :

5. Stack technique & archi

CoucheTechCoût
FrontendVite 7 + React 18 + TypeScript + Tailwind 30 €
HostingCloudflare Pages (bandwidth illimité, custom domain)0 €
API serverlessCloudflare Pages Functions (Workers)0 € jusqu'à 100k req/jour
DatabaseSupabase Postgres 17 (eu-west-3 Paris)0 € jusqu'à 500MB/50k MAU
Auth walletSIWS (Sign-In With Solana), signature ed25519 vérifiée serveur0 €
Auth XOAuth 2.0 PKCE0 € (tier Free X)
Vérif RT/CommentTwitter oEmbed publique0 €
DNSCloudflare (registrar = AWS Route 53)~10 €/an domaine

Schéma de la base de données

16 tables actuellement :

Triggers Postgres importants

Sécurité

6. Vérification des tâches X — détails

Pourquoi pas 100% automatique ? L'API X tier Free en 2026 ne permet plus de lire les follows / likes / RT d'un user. Il faut le tier Basic à 200 USD/mois pour ça. On a donc opté pour une approche hybride gratuite.
ActionMéthode actuelleAuto-validé ?
Follow @diggr_appHonor systemNon — revue manuelle
Like d'un tweetHonor systemNon — revue manuelle
Retweet d'un tweetURL submission + oEmbedSouvent oui
Quote tweetURL submission + oEmbedSouvent oui
Comment / ReplyURL submission + oEmbedSouvent oui

Pour les retweets et comments, l'user colle l'URL de son tweet (ex: https://x.com/morgan/status/12345). On fait un appel à https://publish.twitter.com/oembed?url=... (gratuit, sans auth, pas de rate limit publié). L'oEmbed nous renvoie :

Si les 2 matchent → statut "verified", points crédités immédiatement.
Si l'un manque → statut "manual", file d'attente admin.

Faille connue (à l'esprit)

7. Comment marche le référral

Pour gagner +50 pts par filleul, il faut :

  1. Le filleul clique sur ton lien https://diggr.bot/r/abc12xyz
  2. Cookie ref=abc12xyz posé sur son navigateur (TTL 30 jours)
  3. Le filleul connecte X → ligne referrals créée (referrer_id, referee_id, tier=1)
  4. Le filleul connecte son wallet
  5. Le filleul complète les 3 actions du pinned post (like + RT + comment)
  6. La fonction Postgres fn_user_qualified() retourne true
  7. Le trigger trg_check_referral_reward_sub crédite +50 pts au parrain
  8. referrals.reward_credited = true (pour ne pas re-créditer)
  9. users.active_referrals du parrain s'incrémente automatiquement

Anti-abuse

8. Bot Telegram — statut

Status : optionnel, non câblé dans l'UI pour l'instant.

La DB a une colonne telegram_user_id et le bot est sur ton EC2. Pour brancher la vérification du join, il suffit de :

  1. Ajouter une commande /link dans le bot qui appelle POST /api/auth/telegram avec un HMAC signé
  2. L'app appelle https://api.telegram.org/bot{TOKEN}/getChatMember?chat_id=...&user_id=... (gratuit, instant)
  3. Si status ∈ {member, administrator, creator} → crédit +20 pts bonus

C'est ~2h de dev quand tu décideras de l'activer. Pour l'instant le focus c'est X comme tu l'as demandé.

9. Coût actuel et future bascule payante

Aujourd'hui — 100% gratuit

0 €/mois jusqu'à environ 5 000 utilisateurs actifs. Au-delà, voici les seuils :

StadeUsersActionCoût
MVP / Beta0–5 0000 €
Croissance5k–20kSi la file d'attente admin devient ingérable → X API Basic~200 USD/mois
Mature20k++ Supabase Pro + CF Workers Paid~250 USD/mois

Quand passer X API Basic ?

Le tier Basic à 200 USD/mois donne :

Le code est déjà préparé pour ça : il suffira d'ajouter un endpoint serveur qui appelle l'API X au lieu de bumper le statut en "manual". La table post_submissions avec son colonne status supporte déjà le switch transparent.