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.
/admin avec 3 onglets : Posts, Submissions, UsersX_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.
@diggr_app (ou celui qu'on utilise)https://diggr.bot/api/auth/x/callbackhttps://diggr.botdiggr-appX_CLIENT_ID : remplace PLACEHOLDER_TO_BE_SET par le vrai Client IDX_CLIENT_SECRET : remplace par le vrai Client Secret (laisse "encrypted")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.
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" :
https://x.com/diggr_app/status/12345...L'ancien placeholder sera automatiquement désactivé (max 1 pinned actif).
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é.
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.
Sur la section "Engagement Tasks" il voit :
Chaque post affiche 3 actions :
| Action | Vérification |
|---|---|
| Like | Honor system → marqué "Pending review" → admin valide en batch dans le panel |
| Retweet | L'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é |
| Comment | Pareil : URL de son reply, oEmbed vérifie l'auteur |
Si oEmbed n'arrive pas à confirmer (tweet supprimé, profile privé, etc.) → fallback en revue manuelle.
L'user a un lien https://diggr.bot/r/abc12xyz. Quand quelqu'un clique :
ref=abc12xyz posé pour 30 joursactive_referrals du parrain s'incrémenteUn user ne peut être référé qu'une seule fois (contrainte DB UNIQUE).
Tu peux :
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é.
Recherche par handle X, wallet ou slug. Pour chaque user :
| Couche | Tech | Coût |
|---|---|---|
| Frontend | Vite 7 + React 18 + TypeScript + Tailwind 3 | 0 € |
| Hosting | Cloudflare Pages (bandwidth illimité, custom domain) | 0 € |
| API serverless | Cloudflare Pages Functions (Workers) | 0 € jusqu'à 100k req/jour |
| Database | Supabase Postgres 17 (eu-west-3 Paris) | 0 € jusqu'à 500MB/50k MAU |
| Auth wallet | SIWS (Sign-In With Solana), signature ed25519 vérifiée serveur | 0 € |
| Auth X | OAuth 2.0 PKCE | 0 € (tier Free X) |
| Vérif RT/Comment | Twitter oEmbed publique | 0 € |
| DNS | Cloudflare (registrar = AWS Route 53) | ~10 €/an domaine |
16 tables actuellement :
users — identité (wallet, x, telegram, slug, points, tier, streak, disqualified)admin_posts — les posts X gérés par admin (1 pinned + jusqu'à 3 daily)post_submissions — preuves utilisateurs (like/RT/comment) avec statutreferrals — liens parrain ↔ filleulpoints_log — audit immutable de tous les changements de pointsauth_nonces — anti-replay SIWS (TTL 5 min)oauth_states — PKCE state pour OAuth X (TTL 10 min)achievements / user_achievements — badges (15 seeds déjà créés)missions / mission_progress — missions multi-étapesboost_windows — fenêtres temporelles X1.5 / X2 sur les pointsseasons — saisons (Genesis Season déjà active)user_events — feed d'événements pour notificationstasks / completions — anciennes tasks "génériques" (Follow X / Follow TG)trg_log_points_on_completion — crédit auto + log + anti-doublontrg_check_referral_reward — +50 pts au parrain quand filleul qualifiétrg_check_referral_reward_sub — pareil mais déclenché sur submission verifiedtrg_award_submission_points — points/3 par action verifiedtrg_update_streak — streak des jours consécutifstrg_update_tier — recalc tier free/insider/premium/ultimate autohttpOnly + Secure + SameSite=Lax (7 jours)is_admin en DB (pas une whitelist en code)secret_text Cloudflare (chiffré au repos)| Action | Méthode actuelle | Auto-validé ? |
|---|---|---|
| Follow @diggr_app | Honor system | Non — revue manuelle |
| Like d'un tweet | Honor system | Non — revue manuelle |
| Retweet d'un tweet | URL submission + oEmbed | Souvent oui |
| Quote tweet | URL submission + oEmbed | Souvent oui |
| Comment / Reply | URL submission + oEmbed | Souvent 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 :
author_name — on vérifie qu'il match le handle du user loguétweet_id ou la mention de l'originalSi les 2 matchent → statut "verified", points crédités immédiatement.
Si l'un manque → statut "manual", file d'attente admin.
author_name de l'URL match user.x_username.https://diggr.bot/r/abc12xyzref=abc12xyz posé sur son navigateur (TTL 30 jours)referrals créée (referrer_id, referee_id, tier=1)fn_user_qualified() retourne truetrg_check_referral_reward_sub crédite +50 pts au parrainreferrals.reward_credited = true (pour ne pas re-créditer)users.active_referrals du parrain s'incrémente automatiquementreferrals.referee_id)disqualified sont exclus du leaderboard et de tous les rewardsLa DB a une colonne telegram_user_id et le bot est sur ton EC2. Pour brancher la vérification du join, il suffit de :
/link dans le bot qui appelle POST /api/auth/telegram avec un HMAC signéhttps://api.telegram.org/bot{TOKEN}/getChatMember?chat_id=...&user_id=... (gratuit, instant)status ∈ {member, administrator, creator} → crédit +20 pts bonusC'est ~2h de dev quand tu décideras de l'activer. Pour l'instant le focus c'est X comme tu l'as demandé.
0 €/mois jusqu'à environ 5 000 utilisateurs actifs. Au-delà, voici les seuils :
| Stade | Users | Action | Coût |
|---|---|---|---|
| MVP / Beta | 0–5 000 | — | 0 € |
| Croissance | 5k–20k | Si la file d'attente admin devient ingérable → X API Basic | ~200 USD/mois |
| Mature | 20k+ | + Supabase Pro + CF Workers Paid | ~250 USD/mois |
Le tier Basic à 200 USD/mois donne :
GET /2/users/:id/following etc.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.