Files
pyre/docs/ARCHITECTURE.md
RogueWave c20094ab56 chore: scaffold PYRE MVP monorepo (structure + docs)
pnpm + TypeScript workspace per design doc §13:
- apps/{web,api,worker} skeletons (Next.js 16, Fastify 5, BullMQ)
- packages/{core,solana,prometheus,db,config} (core has real types/DTOs;
  solana/prometheus are stubs)
- programs/pyre-core placeholder (future Anchor, v1.0)
- docs/: PYRE_MVP_DESIGN (canonical), ARCHITECTURE, SECURITY, TOKEN_CLASSIFICATION
- CLAUDE.md, README, .env.example (no private-key var by design)

Skeleton + docs only — no Solana/business logic yet. All workspaces typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 02:20:55 +00:00

490 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PYRE — Engineering Architecture
> Companion to [`PYRE_MVP_DESIGN.md`](./PYRE_MVP_DESIGN.md). The design document is
> the canonical source of truth; this file describes *how the system is wired
> together*. Where they appear to disagree, the design document wins.
**Tagline:** *Burn the dead. Feed the PYRE. Claim the Spawn.*
---
## 1. System Overview
PYRE is a Solana wallet-cleanup and ritual meme-rebirth protocol. The MVP runs as
three runtime services backed by two stateful stores, and it depends on two
classes of external service: a Solana RPC provider and AI APIs.
Runtime services:
- **`apps/web`** (`pyre-web`) — Next.js frontend. Wallet connect, scanner UI,
cleanup preview, signing, receipt rendering, Prometheus review, admin pages.
- **`apps/api`** (`pyre-api`) — Node.js/Fastify (or Express) HTTP API. Scan
coordination, classification, **unsigned** transaction building, receipt
storage, AI orchestration, admin API. The only service the browser talks to.
- **`apps/worker`** (`pyre-worker`) — Node.js BullMQ worker. Slow/async jobs:
metadata enrichment, AI generation, image prompts, safety/collision checks,
confirmation tracking, receipt enrichment.
Stateful stores:
- **PostgreSQL** — durable record of scans, classifications, receipts,
generations, and Spawn records.
- **Redis** — BullMQ job queue, scan cache, rate limiting, quote cache,
generation status.
External dependencies (never self-hosted on the MVP VPS):
- **Solana RPC** — external provider only. No validator/RPC node on the VPS.
- **AI APIs** — text, image, and moderation APIs only. No local LLM/image models.
### Component / Data-Flow Diagram
```
┌──────────────┐
│ Wallet │ (Phantom / Solflare via Wallet Adapter)
│ (browser) │ signs locally — keys never leave the client
└──────┬───────┘
│ connect / sign / send
┌──────────────┐ static assets / SSR
│ apps/web │◀───────────────────────────┐
│ (Next.js) │ │
└──────┬───────┘ │
│ HTTPS (JSON) │
▼ │
┌───────────────────────────────────────────────┐ │
│ apps/api │ │
│ scan · classify · build (UNSIGNED) · receipt │ │
│ prometheus/generate · admin │ │
└───┬─────────────┬──────────────┬────────────────┘ │
│ │ │ │
│ SQL │ cache/queue │ getAccounts / simulate / │
▼ ▼ │ sendTx / confirm │
┌──────────┐ ┌──────────┐ ▼ │
│ Postgres │ │ Redis │ ┌──────────────┐ │
│ │ │ (BullMQ) │ │ Solana RPC │ (external) │
└──────────┘ └────┬─────┘ └──────────────┘ │
│ │
│ jobs pulled from queue │
▼ │
┌──────────────┐ ┌──────────────┐ │
│ apps/worker │───▶│ AI APIs │ (external) │
│ (BullMQ) │ │ text/image/ │ │
│ │ │ moderation │ │
└──────┬───────┘ └──────────────┘ │
│ writes results / status │
├───────────────▶ Postgres │
└───────────────▶ Redis ────────────────────┘
(generation status read back by web/api)
```
The browser only ever talks to `apps/web` and `apps/api`. The worker is not
network-exposed; it consumes jobs from Redis and writes results back to Postgres
and Redis. RPC and AI calls flow outbound only.
---
## 2. Component Responsibilities
### `apps/web` — User-facing frontend
Next.js + TypeScript + Tailwind + Solana Wallet Adapter, with React Query or
Zustand for state. Responsibilities (§11):
- Wallet connect via Solana Wallet Adapter.
- Token-account display and classification grouping (closeable / burnable /
transmutable / protected / unsupported).
- User confirmations and **transaction preview** UI.
- Transaction **signing** (client-side, via the connected wallet only).
- Receipt rendering and optional share image.
- Prometheus Spawn-package review and public round/Spawn pages.
- Admin / generation review UI.
### `apps/api` — Backend HTTP API
Node.js + Fastify/Express + TypeScript, fronting PostgreSQL, Redis, BullMQ.
Responsibilities (§11):
- Token-scan coordination (calls RPC, persists results).
- Classification helpers and route evaluation.
- **Builds UNSIGNED Solana transactions** — never signs, never holds keys.
- Metadata preparation and AI generation orchestration (enqueues worker jobs).
- Receipt storage and Spawn-record storage.
- Public API and protected admin API.
### `apps/worker` — Background worker
Node.js worker process driven by BullMQ over Redis, with AI API clients.
Responsibilities (§11):
- Slow token-metadata enrichment.
- AI generation jobs (Prometheus).
- Image-prompt generation.
- Safety checks and ticker/name collision checks.
- Background confirmation tracking.
- Receipt enrichment.
### `packages/core` — Shared types & business logic
The single home for cross-service domain definitions (§13):
- Classification **enums**: `EMPTY_CLOSE_ONLY`, `INCINERATE_ONLY`,
`TRANSMUTABLE`, `PROTECTED_SKIP`, `UNSUPPORTED`.
- Conservative **risk rules** (the §7 safety rules: classic SPL only, skip
Token-2022/NFTs/LP/frozen/delegated, USD threshold, price-impact and stale-quote
guards).
- Shared **DTOs** for the API request/response shapes.
- **Receipt schema**.
- **Prometheus input/output schema**.
### `packages/solana` — Solana transaction helpers
Everything that touches the chain at the instruction level (§13):
- Token-account **parsing** (decode raw account state into the scan model).
- **Close-account** transaction builder.
- **Burn** transaction builder.
- **Simulation** helpers (simulate before signing — §7).
- **Transaction decoder** (decode the built tx so it can be matched against the
preview — §8 step 5, §16).
### `packages/prometheus` — AI generation logic
The creative engine's code (§13), invoked by the worker:
- Prompt **templates**.
- The **meta mixer** (probabilistic influence blend — §9).
- Output **parser**.
- **Safety checks** (blocked terms, scam/impersonation/copyright filters).
- **Image-prompt generator**.
### `packages/db` — Database layer
Schema, migrations, and table definitions (§13/§15). Owns the canonical SQL and
migration history; `apps/api` and `apps/worker` depend on it for data access.
### `packages/config` — Shared config
Shared configuration and environment loading (§13). Centralizes reading
`.env`-supplied secrets (RPC URL, AI keys, DB/Redis connection strings) so no
secret is hard-coded.
### `programs/pyre-core` — Future Anchor program
NOT part of the first burner MVP. The future on-chain trust core (rounds, Essence
vault, claims, refunds) — built only at Phase 7 / v1.0.
---
## 3. Request / Data Flow — The Burner Journey
The core flow is the 8-step burner sequence from §8. The critical trust property:
**the server builds an UNSIGNED transaction, the client signs it, and the decoded
transaction is matched against the preview before signing.**
```
1. Connect ──▶ 2. Scan ──▶ 3. Classify ──▶ 4. Preview ──▶ 5. Build (UNSIGNED)
8. Receipt ◀── 7. Confirm ◀── 6. Sign (client) ◀── decode & match against preview
```
1. **Wallet Connect** — user connects via Solana Wallet Adapter (`apps/web`).
No keys leave the browser.
2. **Account Scan**`apps/web` calls `POST /api/scan`. `apps/api` queries token
accounts via the external RPC, capturing for each: owner, ATA address, mint,
token program, balance, decimals, rent estimate, metadata (if available),
token-program type, frozen/delegated state. Results persist to
`wallet_scans` / `token_accounts`; slow metadata enrichment may be deferred to
a worker job. Scan results are cached in Redis.
3. **Classification** — each account is classified server-side into the §6
categories and grouped for the UI. **Client-submitted classifications are not
trusted** — the server recomputes where needed (§16).
4. **Preview** — before any signing the user sees: accounts to close, tokens to
burn, accounts skipped, estimated rent returned, transaction fees, warnings,
and the destination wallet for recovered rent (which is the user's own wallet).
5. **Build Transaction**`apps/web` calls `POST /api/build/close-empty` (and/or
`/api/build/burn`). `apps/api` uses `packages/solana` to build an **unsigned**
transaction and returns it base64-encoded plus the preview. The client decodes
the transaction (`packages/solana` decoder) and **matches it against the
preview**; any mismatch aborts before signing.
6. **User Signs** — locally, with the connected wallet. PYRE never requests
private keys and never performs custodial signing.
7. **Confirmation** — the signed transaction is sent and confirmed via RPC. A
worker confirmation-tracking job may follow the signature to durable finality.
8. **Receipt**`apps/web` calls `POST /api/receipt`; `apps/api` records and
returns the receipt: tx signature, accounts closed, tokens burned, rent
returned, accounts skipped, warnings, timestamp, optional share image. A worker
receipt-enrichment job may backfill metadata.
All transactions are simulated before final signing (§7), and all build requests
are logged (§16).
---
## 4. API Surface
Reproduced from §14. All endpoints are served by `apps/api`. Admin endpoints are
authenticated and protected separately (§16).
### `POST /api/scan`
```jsonc
// in:
{ "wallet": "wallet_pubkey" }
// out:
{
"scanId": "uuid",
"wallet": "wallet_pubkey",
"summary": {
"totalAccounts": 0,
"emptyCloseOnly": 0,
"incinerateOnly": 0,
"transmutable": 0,
"protectedSkip": 0,
"unsupported": 0,
"estimatedRentLamports": 0
},
"accounts": []
}
```
### `POST /api/build/close-empty`
```jsonc
// in:
{ "wallet": "...", "accountAddresses": ["ata1", "ata2"] }
// out:
{
"transactionBase64": "...",
"preview": {
"accountsToClose": [],
"estimatedRentReturnedLamports": 0,
"rentDestination": "user_wallet_pubkey"
}
}
```
### `POST /api/build/burn`
```jsonc
// in:
{ "wallet": "...", "items": [{ "tokenAccount": "...", "mint": "...", "amount": "..." }] }
// out:
{
"transactionBase64": "...",
"preview": {
"tokensToBurn": [],
"accountsPotentiallyClosable": []
}
}
```
### `POST /api/receipt`
```jsonc
// in:
{ "wallet": "...", "txSignature": "...", "scanId": "uuid" }
// out:
{
"receiptId": "uuid",
"txSignature": "...",
"rentReturnedLamports": 0,
"closedAccounts": [],
"burnedTokens": [],
"skippedTokens": []
}
```
### `POST /api/prometheus/generate`
```jsonc
// in:
{ "receiptId": "uuid", "chaos": 0.25, "operatorSeed": "optional" }
// out:
{
"generationId": "uuid",
"spawnName": "...",
"ticker": "...",
"lore": "...",
"imagePrompt": "...",
"metadata": {},
"riskFlags": []
}
```
### Admin endpoints
Admin / generation-review endpoints (approve/reject generations, record Pump.fun
launches, view system events) are protected and not part of the public surface.
They back the admin review UI and the Spawn-record workflow (§10, §16).
---
## 5. Data Model
### Initial PostgreSQL tables (§15)
```
wallet_scans: id, wallet, status, created_at, completed_at, summary_json
token_accounts: id, scan_id, wallet, ata, mint, token_program,
raw_balance, ui_balance, decimals, symbol, name,
classification, warnings_json, estimated_rent_lamports,
created_at
cleanup_receipts: id, wallet, scan_id, tx_signature, rent_returned_lamports,
closed_accounts_count, burned_tokens_count, status,
created_at, receipt_json
prometheus_generations: id, receipt_id, input_json, output_json, status,
risk_flags_json, created_at, approved_at, rejected_at
spawn_records: id, generation_id, spawn_name, ticker, mint, metadata_uri,
pumpfun_url, launch_tx, status, created_at
```
Additional initial tables called out in §11/§15: `token_classifications`,
`burn_events`, `close_account_events`, `spawn_candidates`, and `system_events`
(audit/event log).
### Future tables (NOT in the burner MVP)
These arrive with the Essence ledger and PYRE Core program (Phases 67):
- `pyre_rounds` — round state machine.
- `essence_contributions` — recorded Essence per wallet per round.
- `claim_records` — Spawn claim accounting.
- `refund_records` — refunds for failed rounds.
- `influence_fields` — meta-influence inputs for Prometheus weighting.
> Per §5/§15: Essence may start in the database, but it must not be called a
> deposit until an on-chain custody model exists, and claims must not be promised
> until claim logic exists.
---
## 6. Redis Usage
Redis serves five roles (§11):
- **Job queue** — backs BullMQ; `apps/api` enqueues, `apps/worker` consumes.
- **Scan cache** — caches scan results so repeat views don't re-hit RPC.
- **Rate limiting** — throttles scan and build endpoints (§16).
- **Temporary quote cache** — short-lived swap/route quotes; stale quotes are
rejected by classification (§7).
- **Generation status** — live status of in-flight Prometheus jobs, read back by
`apps/web` / `apps/api`.
### BullMQ Worker Jobs
`apps/worker` processes these job types (§11):
- **Metadata enrichment** — slow token name/symbol/metadata lookups.
- **AI generation** — Prometheus Spawn generation.
- **Image prompts** — image-prompt generation for the Spawn.
- **Safety checks** — moderation of generated names/tickers/lore.
- **Collision checks** — ticker/name duplicate detection.
- **Confirmation tracking** — follow tx signatures to finality in the background.
- **Receipt enrichment** — backfill receipt detail after confirmation.
---
## 7. Solana RPC Requirements
PYRE uses an **external RPC provider only**. Per §11/§12, the MVP VPS must **not**
run a Solana validator or RPC node.
Required RPC capabilities (§11):
- Get token accounts by owner.
- Get account info.
- Simulate transactions.
- Send transactions.
- Confirm transactions.
- Parse token-account state.
The RPC endpoint URL is supplied via environment config (`packages/config`) and
treated as a secret. All chain access flows through `packages/solana`.
---
## 8. AI Services
AI is **API-based only** (§11/§12). The MVP server must **not** run local LLMs or
local image-generation models.
Service classes used:
- **Text generation** — Spawn name, ticker, lore, tagline, description, launch
copy (§9 outputs).
- **Image generation** — from the generated image prompt.
- **Moderation / safety** — filtering hate/explicit/extremist/copyrighted/
impersonation/scam-like output (§16).
All AI calls are made from `apps/worker` using clients configured via secrets in
`packages/config`. Prometheus generates a *candidate package for human review*
it never launches tokens or controls funds (§9).
---
## 9. Infrastructure & Deployment
A single **8GB VPS** is sufficient for the MVP (§12). It runs:
- `pyre-web`, `pyre-api`, `pyre-worker`
- PostgreSQL
- Redis
- **nginx** (reverse proxy / TLS termination in front of web + api)
- **PM2 or systemd** (process supervision for the three Node services)
- logs / log rotation
- admin dashboard
The VPS must **NOT** run (§12):
- a Solana validator,
- a Solana RPC node,
- a large local LLM,
- local image generation,
- heavy indexing at scale.
**Base setup already completed (§12/§19):** `pyre` user created, root login
disabled, SSH key auth, UFW firewall, Fail2ban, basic hardening.
**Next setup (§12/§19):** Node.js 22, pnpm, Git, nginx, PostgreSQL, Redis, PM2,
Claude Code, project repo, environment files, backup script, log rotation.
**External accounts required (§19):** Solana RPC provider, OpenAI/Anthropic API
key, image-generation provider, domain name, GitHub repo, Pump.fun creator
wallet, optional IPFS/Arweave metadata service.
---
## 10. Build-Order Note (Phased Roadmap)
Components map to the §18 development phases so a reader knows *what gets built
when*:
| Phase | Focus | Components touched |
|-------|-------|--------------------|
| **0 — Server & Repo Setup** | VPS, pnpm workspace, web/api/worker skeletons, Postgres + Redis, nginx, env templates | all apps (skeleton), `packages/config`, `infra/` |
| **1 — Wallet Scanner** | Wallet connect, scan endpoint, token-account fetch, basic classification, results + protected/skipped UI | `apps/web`, `apps/api`, `packages/solana` (parsing), `packages/core` (enums/rules), `packages/db` (`wallet_scans`, `token_accounts`) |
| **2 — Close Empty ATAs** | Build close-account tx, decode/preview, signing, confirmation tracking, receipt page | `packages/solana` (close builder + decoder + simulation), `apps/api` (`/build/close-empty`, `/receipt`), `apps/worker` (confirmation tracking), `packages/db` (`cleanup_receipts`, `close_account_events`) |
| **3 — Burn Junk** | `INCINERATE_ONLY` classification, burn builder, burn-then-close, stronger confirmations, receipt update | `packages/solana` (burn builder), `apps/api` (`/build/burn`), `packages/db` (`burn_events`) |
| **4 — Prometheus Generator** | Generation input from receipt, meta mixer, name/ticker/lore + image prompt, safety checks, admin approval UI | `packages/prometheus`, `apps/worker` (AI/safety/collision jobs), `apps/api` (`/prometheus/generate`, admin), `apps/web` (review UI), `packages/db` (`prometheus_generations`, `spawn_candidates`) |
| **5 — Manual Pump.fun Launch** | Approved package, metadata JSON, operator checklist, record mint/url/tx, public Spawn page | `apps/web` (public Spawn page), `apps/api` (admin record endpoints), `packages/db` (`spawn_records`) |
| **6 — Essence / Round Prototype** | Swap-candidate detection, route quote preview, net Essence estimate, round dashboard, DB-only contribution record (no claim promises) | `packages/solana` (route eval), `apps/api`, `packages/db` (future `pyre_rounds`, `essence_contributions`, `influence_fields`) |
| **7 — PYRE Core Program** | Anchor program: create round, contribute Essence, contribution-receipt PDA, lock round, register Spawn, claim, refund, tests | `programs/pyre-core`, future tables `claim_records`, `refund_records` |
The first three phases deliver the trust-building burner (v0.1). The Anchor
program in `programs/pyre-core` is explicitly **not** needed until Phase 7 / v1.0.
---
> **PYRE returns your rent. The scraps feed the fire.**