Annexe F · Mise en place du projet
Tout ce qu'il faut pour démarrer le code le premier jour : structure du repo, comptes et clés à créer, variables d'environnement, lancement en local, workers et tâches planifiées, déploiement.
Structure du repo#
Un seul repo (monorepo pnpm + Turborepo), TypeScript partout sauf les contrats.
vivra/
├── apps/
│ ├── web/ # Next.js : landing + dapp (4 écrans)
│ ├── admin/ # Next.js : back-office (SIWE)
│ ├── api/ # serveur HTTP + WebSocket (Fastify)
│ └── workers/ # BullMQ : analyse, suivi, orchestrateur, agents, buyback, trésorerie, bots
├── packages/
│ ├── db/ # schéma, migrations, client (annexe A)
│ ├── core/ # logique métier pure : statuts, score de reprise, règles de vote
│ ├── chain/ # config des chaînes, ABI, lectures et écritures viem (annexe D)
│ ├── agents/ # specs YAML, prompts, schémas de sortie, outils (annexe C)
│ ├── templates/ # templates de sites, de visuels et de mini-apps
│ └── ui/ # composants partagés, tokens de la DA
├── contracts/ # Foundry : BuybackBurner + tests
├── infra/ # Dockerfiles, docker-compose, config du déploiement
└── .github/workflows/ # CIComptes et clés à créer (jalon M0)#
| Service | Pour quoi | Variable |
|---|---|---|
| Alchemy (Robinhood Chain) | RPC principal mainnet et testnet | RPC_URL_MAINNET, RPC_URL_TESTNET |
| Second fournisseur RPC | secours | RPC_URL_MAINNET_FALLBACK |
| Surplus Intelligence | inférence des agents | SURPLUS_API_KEY, SURPLUS_BASE_URL |
| Générateur d'images (via Surplus si disponible, sinon un fournisseur dédié) | Designer | IMAGE_API_KEY |
| API X (offre payante en écriture) | posts du compte Vivra et des tokens CTO | X_API_KEY, X_API_SECRET, puis un jeton OAuth par compte stocké en base, chiffré |
| Telegram (@BotFather) | bot Vivra et TG Bot | TELEGRAM_BOT_TOKEN, TELEGRAM_ALERTS_CHAT_ID |
| Service d'emails (Resend ou Postmark) | lien magique et code | EMAIL_API_KEY, EMAIL_FROM |
| Captcha invisible (Cloudflare Turnstile) | inscription | TURNSTILE_SECRET |
| Cloudflare Pages (ou Vercel) | sites des tokens CTO | PAGES_API_TOKEN, PAGES_ACCOUNT_ID |
| DNS du domaine Vivra (Cloudflare) | sous-domaines <ticker>.<domaine> | DNS_ZONE_ID |
| Stockage objet (Cloudflare R2 ou S3) | visuels et memes | S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY |
| Hébergeur de conteneurs (Railway, Fly.io ou Render) | API et workers | côté hébergeur |
| Postgres managé + Redis managé | données et files | DATABASE_URL, REDIS_URL |
| Coffre de secrets (celui de l'hébergeur ou Doppler) | clés des hot wallets | voir ci-dessous |
| Sentry | erreurs | SENTRY_DSN |
Variables d'environnement#
Un fichier .env.example commité, sans aucune valeur secrète. Les vraies valeurs vivent dans le coffre de secrets.
# Général
NODE_ENV=development
APP_URL=http://localhost:3000
API_URL=http://localhost:4000
CHAIN_ENV=testnet # testnet | fork | mainnet
# Données
DATABASE_URL=postgres://vivra:vivra@localhost:5432/vivra
REDIS_URL=redis://localhost:6379
# Sécurité
SESSION_SECRET= # 32 octets aléatoires
EMAIL_HMAC_KEY= # pour users.email_hash
EMAIL_ENC_KEY= # AES-256-GCM pour users.email_enc
SLICE_SCHEDULE_KEY= # chiffre les horaires des tranches
# Chaîne
RPC_URL_TESTNET=
RPC_URL_MAINNET=
RPC_URL_MAINNET_FALLBACK=
BUYBACK_BURNER_ADDRESS=
BUYBACK_HOT_WALLET_KEY_REF= # référence dans le coffre, jamais la clé elle-même
AI_HOT_WALLET_KEY_REF=
TREASURY_OPERATOR_KEY_REF= # signe les claims de l'escrow (wallets Collecte et Frais CTO)
# Inférence et services
SURPLUS_BASE_URL=https://api.surplusintelligence.ai/v1
SURPLUS_API_KEY=
IMAGE_API_KEY=
X_API_KEY=
X_API_SECRET=
TELEGRAM_BOT_TOKEN=
TELEGRAM_ALERTS_CHAT_ID=
EMAIL_API_KEY=
EMAIL_FROM=vote@<domaine-vivra>
TURNSTILE_SECRET=
PAGES_API_TOKEN=
PAGES_ACCOUNT_ID=
DNS_ZONE_ID=
S3_ENDPOINT=
S3_BUCKET=
S3_ACCESS_KEY=
S3_SECRET_KEY=
SENTRY_DSN=Les clés privées des hot wallets ne sont jamais dans une variable d'environnement lisible par tous les services : seul le worker concerné lit sa clé depuis le coffre, au démarrage.
Lancer en local#
pnpm install
docker compose -f infra/docker-compose.yml up -d # Postgres 16 + Redis 7
pnpm db:migrate && pnpm db:seed # seed : 30 tokens fictifs, 1 cycle, 1 opération de démo
pnpm dev # web :3000, admin :3001, api :4000, workers
cd contracts && forge test # tests du BuybackBurner
forge test --fork-url $RPC_URL_MAINNET # tests sur un fork du mainnetpnpm dev lance les workers en mode CHAIN_ENV=testnet : aucune écriture mainnet n'est possible tant que CHAIN_ENV ne vaut pas mainnet.
Files et tâches planifiées (BullMQ)#
| File | Déclencheur | Rôle |
|---|---|---|
projects.analyze | à la soumission d'une adresse par l'équipe, ou relance | analyse complète d'un token par le Scanner |
tracking.candidates | toutes les 15 min, les 5 candidats du vote en cours | marché en direct, score de reprise en direct |
tracking.live | en continu, le token CTO en opération seulement (events de son pool ou de sa courbe) | chart, tranches, war room |
tracking.followup | toutes les heures, tokens repris jusqu'à J+30 | suivi, verdict, passation |
cycles.clock | toutes les minutes | ouvrir et fermer les votes, créer l'opération à J0 |
orchestrator.tick | toutes les minutes | lancer les étapes dues (annexe C) |
agents.run | à la demande de l'orchestrateur | exécuter un agent, concurrence 3 |
tg.updates | webhook Telegram | anti-spam et réponses du TG Bot |
buyback.slices | job différé par tranche, à l'horaire tiré | exécuter une tranche |
buyback.refill | 1 fois par jour | recharger le hot wallet depuis la réserve |
treasury.daily | 1 fois par jour, 00:30 UTC | balayage, claim, répartition, recharge Surplus, registre |
social.publish | toutes les minutes | publier les posts validés dont l'heure est passée |
alerts.check | toutes les minutes | seuils de la page Sécurité |
Chaque job est idempotent : un job relancé après un crash ne refait pas une transaction déjà envoyée (on vérifie tx_hash en base avant d'envoyer).
Déploiement#
| Environnement | Où | Quand |
|---|---|---|
| Preview | une URL par pull request (front) | à chaque PR |
| Staging | hébergeur de conteneurs + testnet Robinhood Chain | à chaque merge sur main |
| Pré-production | staging pointé sur un fork du mainnet | avant le lancement (jalon M5) |
| Production | hébergeur de conteneurs + mainnet | tag v*, déclenché à la main |
CI (GitHub Actions) à chaque PR : lint, types, tests unitaires, forge test, build des apps, scan de secrets (gitleaks). Un merge est bloqué si une étape échoue.
Ordre de travail conseillé#
Le plan de développement donne les jalons. Dans le code, l'ordre qui évite de se bloquer :
packages/dbetpackages/chain(schéma, config, ABI).- Analyse à la demande et score de reprise, avec le back-office de soumission et de relecture (jalon M1).
- Orchestrateur avec des agents « factices » qui renvoient des sorties fixes, puis les vrais agents un par un (jalon M2).
- BuybackBurner sur testnet, puis Buyback Bot et trésorerie (jalon M3).
- Vote, back-office, dapp complète, bots (jalon M4).
- Répétition d'un cycle entier sur le fork (jalon M5).