# 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.

```text
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/  # CI
```

## Comptes 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.

```bash
# 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

```bash
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 mainnet
```

`pnpm 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 :

1. `packages/db` et `packages/chain` (schéma, config, ABI).
2. Analyse à la demande et score de reprise, avec le back-office de soumission et de relecture (jalon M1).
3. Orchestrateur avec des agents « factices » qui renvoient des sorties fixes, puis les vrais agents un par un (jalon M2).
4. BuybackBurner sur testnet, puis Buyback Bot et trésorerie (jalon M3).
5. Vote, back-office, dapp complète, bots (jalon M4).
6. Répétition d'un cycle entier sur le fork (jalon M5).
