vivraDocumentationV1Comprendre le vote

Conventions (for Claude Code)

Rules every ticket follows. If a ticket and this page disagree, the ticket wins for that ticket only.

Folder layout#

text
vivra/
├── CLAUDE.md
├── apps/
│   ├── web/        Next.js 15: landing (/), dapp (/vote, /dossiers/[id], /war-room/[id], /ledger)
│   ├── admin/      Next.js 15: back-office (SIWE login), /projects, /cycles, /validations, /operations, /settings
│   ├── api/        Fastify 5: src/routes/<domain>.ts, src/plugins/*, src/ws.ts
│   └── workers/    BullMQ: src/queues/<queue>.ts, src/jobs/<job>.ts, src/scheduler.ts
├── packages/
│   ├── config/     env loading + validation (zod), shared constants
│   ├── db/         src/schema/*.ts (Drizzle), migrations/, src/seed.ts, src/client.ts
│   ├── core/       pure logic: status machine, dead/target/safety checks, recovery score, buyback planner, vote rules
│   ├── chain/      src/config.ts, src/abi/*.json, src/read/*.ts, src/write/*.ts, src/logs.ts
│   ├── agents/     src/llm.ts, src/runner.ts, src/tools/*.ts, src/specs/*.yaml, src/prompts/*.md, src/schemas/*.ts
│   ├── templates/  sites/, utilities/, brand/ (each template = folder + manifest.json)
│   └── ui/         React components + tokens (colors, type, radii)
├── contracts/      Foundry: src/BuybackBurner.sol, test/, script/
└── infra/          docker-compose.yml, Dockerfiles, deploy config

TypeScript#

  • strict: true, noUncheckedIndexedAccess: true. No any (use unknown + zod).
  • ESM everywhere. Path aliases: @vivra/db, @vivra/core, @vivra/chain, @vivra/agents, @vivra/config, @vivra/ui.
  • Amounts: bigint for wei and raw token units. Convert with helpers in @vivra/core/money only: toWei, fromWei, formatToken, usd(value: string).
  • Dates: Date in UTC, ISO strings over the wire. Helpers in @vivra/core/time: T(j0, hours), J(j0, days).

API#

  • One Fastify plugin per domain: auth, cycles, votes, candidates, operations, ledger, admin.
  • Every route declares zod body/querystring/params and response schemas (fastify-type-provider-zod).
  • Errors: throw ApiError(code, httpStatus, message); a global handler maps to { error: { code, message } }. Codes: annexe B.
  • Rate limits with @fastify/rate-limit, values from annexe B.
  • Sessions: cookie vivra_session (HttpOnly, Secure, SameSite=Lax). Admin: vivra_admin via SIWE.

Database#

  • Drizzle schema mirrors annexe A exactly (names, types, enums). Any deviation = a note in the PR.
  • Migrations are generated (pnpm db:generate), never hand-edited after merge.
  • Append-only tables (log_entries, ledger_entries, buyback_slices, admin_audit): no UPDATE/DELETE in code, except buyback_slices.status/tx_hash/... transitions done by the executor.
  • Settings: read through getSetting(key) with a typed registry in @vivra/core/settings (default values from the spec).

Workers#

  • One queue per concern (annexe F list). Job names <domain>.<action>.
  • Every job is idempotent: compute a deterministic jobId, and check DB state before side effects.
  • Retries: 3 attempts, backoff 2 min / 10 min / 30 min, then mark failed + alert.
  • Long-running chain reads chunk by block ranges (default 10,000 blocks, configurable).

Chain#

  • All addresses come from @vivra/chain/config per CHAIN_ENV (testnet | fork | mainnet).
  • ABIs are JSON copied from the explorer, never hand-written. Unknown ABI = stop and ask (⚠️ Pons).
  • Writes go through sendTx({ simulate, capCheck, send, waitFor:1, ledger }) in @vivra/chain/write.

Agents#

  • An agent = a YAML spec (specs/<name>.yaml) + a prompt (prompts/<name>.md) + output zod schemas (schemas/<step>.ts) + a tool allowlist.
  • The runner enforces: max 25 tool turns, budget cap in USD, 10 min timeout, schema validation with one retry.
  • Every LLM call and tool call writes a log_entries row with a human summary generated by the runner.

Tests#

  • packages/core: unit tests for every function, including the spec's worked examples (e.g. the recovery score example = 68).
  • packages/chain: tests against recorded fixtures (JSON logs) + an optional testnet suite behind TESTNET=1.
  • apps/api: route tests with an in-memory Fastify instance + a test Postgres (docker).
  • contracts/: Foundry unit + fuzz + fork tests (annexe D table).
  • apps/web: Playwright smoke test per screen.

Pull requests#

  • Branch t<id>-<slug>. Title T<id>: <title>.
  • Description: plan, files touched, decisions taken, the "Done when" checklist with the command used for each item, open questions.
  • No PR mixes two tickets.
↑ ↓ pour parcourir · Entrée pour ouvrirVIVRA DOCS