RMI Backend β 2026 Architecture Design
Why this exists
The current backend (/root/backend/) has grown organically:
main.pyis 10,305 lines- 124 router files flat in
app/routers/ - 14 RAG modules scattered at top of
app/ token_scanner.pyis 4,109 linesx402_tools.pyis 5,817 lines- Cross-cutting concerns (redis, auth, errors) duplicated across modules
- Domain logic entangled with FastAPI
- No tests, no type safety, no clear boundaries
15 mechanical refactor tasks would patch symptoms. This design fixes the architecture.
Target Layout
/root/backend/
βββ pyproject.toml uv + ruff + mypy + pytest config (single source)
βββ .pre-commit-config.yaml ruff + mypy + size cap + gitleaks
βββ Dockerfile
βββ alembic/ async migrations
β
βββ app/
β βββ main.py <100 lines: app factory + lifespan + middleware ONLY
β βββ config.py pydantic-settings, env loading
β β
β βββ core/ cross-cutting, NO business logic
β β βββ logging.py structlog JSON + correlation ID
β β βββ errors.py AppError hierarchy + FastAPI handlers
β β βββ redis.py async client + get_redis() Depends()
β β βββ db.py async SQLAlchemy session
β β βββ auth.py JWT decode + role guards
β β βββ lifespan.py startup/shutdown
β β βββ middleware.py CORS, rate limit, correlation ID
β β βββ websocket.py WS connection manager
β β βββ tracing.py OpenTelemetry + Langfuse v4 init
β β βββ http.py async httpx client
β β βββ pagination.py cursor-based
β β
β βββ api/ HTTP transport, thin routes
β β βββ deps.py shared Depends (current_user, redis, etc)
β β βββ v1/
β β β βββ public/ no auth β scanner, wallet, token, pricing, health
β β β βββ auth/ JWT β portfolio, alerts, intel, profile
β β β βββ admin/ admin β users, system, ops
β β β βββ x402/ paid β tools, tokens, wallets, defi, security
β β β βββ mcp/ MCP β tools.py
β β βββ ws/ WebSocket
β β βββ alerts.py
β β
β βββ domain/ pure business logic, NO FastAPI imports
β β βββ scanner/ core + honeypot + rugcheck + holders + contract + deployer + models + service
β β βββ wallet/ analyzer + labels + behavior + models + service
β β βββ token/ discovery + supply + models + service
β β βββ rag/ embeddings + chunking + search + ingest + firehose + feedback + agentic + evaluation + tracing + router + permanence + models + service
β β βββ x402/ facilitator + tokens + enforcement + settlement + models + service
β β βββ intel/ feeds + narratives + graph + models + service
β β βββ scam/ classifier + patterns + models + service
β β βββ databus/ client + chains(96) + models + service
β β βββ bulletin/ board + models + service
β β
β βββ infra/ external integrations
β β βββ ollama.py
β β βββ langfuse.py
β β βββ vector_store.py
β β βββ chains/ evm + solana + bitcoin + base + ...
β β βββ apis/ coingecko + etherscan + birdeye + goplus + ...
β β βββ providers/ ollama + openrouter + huggingface + ...
β β
β βββ workers/ background jobs (separate from API)
β βββ firehose.py
β βββ scanner_queue.py
β βββ ingest_cron.py
β βββ cleanup.py
β
βββ tests/
βββ conftest.py
βββ unit/domain/
βββ integration/api/v1/
Key Design Principles
- STRICT LAYERING.
api β domain β infra. Never reverse. Domain knows nothing about HTTP. - ONE SOURCE OF TRUTH for cross-cutting. redis/auth/errors/logging live in
core/exactly once. Routes import, never redefine. - HARD SIZE CAP. 500 lines per file. Enforced in pre-commit. No 4,109-line
token_scanner.pyever again. - THIN ROUTES. Routes parse β call service β return. No business logic in HTTP layer.
- DOMAIN = PURE PYTHON.
domain/scanner/can be unit tested without spinning up FastAPI. This is the test that proves the architecture. - WORKERS SEPARATED. Background jobs don't pollute the API. firehose, scanner_queue, ingest_cron live in
workers/. - PYDANTIC V2 EVERYWHERE. Every domain has
models.py. Nodicttypes crossing boundaries. - ASYNC-ONLY. No sync I/O in handlers. Same shape for the whole codebase.
- OBSERVABILITY BY DEFAULT. structlog JSON + correlation ID + OTel + Langfuse in
core/tracing.py. Every endpoint instrumented without opt-in. - STRANGLER FIG MIGRATION. New skeleton co-exists with old code. Old
main.pykeeps importing the old routers. New routes added alongside. Per-domain cutover, not big-bang.
Migration Order
| Order | Domain | Why |
|---|---|---|
| 0 | rag_engine shim |
unblock prod crash, temp until app/rag/ lands |
| 1 | core/ |
foundation everyone depends on |
| 2 | infra/ |
external integrations domain depends on |
| 3 | alerts |
smallest, well-bounded, has WS + JWT + redis β proves full pattern |
| 4 | wallet |
high-value, used by frontend |
| 5 | token |
high-value |
| 6 | scanner |
biggest (4,109 lines), do last when pattern is mature |
| 7 | x402 |
payment system, critical, mature pattern by then |
| 8 | intel, scam, databus, bulletin |
long tail |
| 9 | rag consolidation (was 14 files) |
last because it's the most coupled |
What Ships This Pass (Foundation)
- Fix crash β
rag_enginere-export shim, backend healthy pyproject.tomlβ uv + ruff + mypy strict + pytest.pre-commit-config.yamlβ ruff + mypy + size cap (500) + gitleaksapp/core/β 11 modules, each <200 linesapp/api/v1/__init__.pyβ router aggregator that still imports OLD routers (zero breakage)app/main.pyβ rewritten to ~100 lines, calls lifespan + middleware fromcore/, mounts new aggregator- Verify: backend boots, all 757 routes respond, health 200, no import errors
- Commit + deploy
What Does NOT Ship This Pass
- Migrating alerts/wallet/token/scanner to new
domain/. That's Phase 2. - The 15 mechanical refactors. Replaced with the layered architecture.
- Deleting old code. Strangler fig β old stays until domain is migrated.
Phase 2: Alerts Vertical Slice (proves the pattern)
After foundation lands, migrate alerts end-to-end as the reference:
app/domain/alerts/
βββ models.py # Alert, AlertRule, Notification β Pydantic v2
βββ repository.py # async SQLAlchemy queries
βββ service.py # business logic, pure Python
βββ broadcaster.py # WebSocket broadcast helper
app/api/v1/auth/alerts.py # thin route: parse β call service β return
This proves the pattern works: domain is pure Python, route is <100 lines, can be unit tested without HTTP.
When alerts is shipped and verified in prod, the same pattern is applied to wallet, token, scanner, etc.