File size: 7,750 Bytes
6993919 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | # RMI Backend β 2026 Architecture Design
## Why this exists
The current backend (`/root/backend/`) has grown organically:
- `main.py` is 10,305 lines
- 124 router files flat in `app/routers/`
- 14 RAG modules scattered at top of `app/`
- `token_scanner.py` is 4,109 lines
- `x402_tools.py` is 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
1. **STRICT LAYERING.** `api β domain β infra`. Never reverse. Domain knows nothing about HTTP.
2. **ONE SOURCE OF TRUTH for cross-cutting.** redis/auth/errors/logging live in `core/` exactly once. Routes import, never redefine.
3. **HARD SIZE CAP.** 500 lines per file. Enforced in pre-commit. No 4,109-line `token_scanner.py` ever again.
4. **THIN ROUTES.** Routes parse β call service β return. No business logic in HTTP layer.
5. **DOMAIN = PURE PYTHON.** `domain/scanner/` can be unit tested without spinning up FastAPI. This is the test that proves the architecture.
6. **WORKERS SEPARATED.** Background jobs don't pollute the API. firehose, scanner_queue, ingest_cron live in `workers/`.
7. **PYDANTIC V2 EVERYWHERE.** Every domain has `models.py`. No `dict` types crossing boundaries.
8. **ASYNC-ONLY.** No sync I/O in handlers. Same shape for the whole codebase.
9. **OBSERVABILITY BY DEFAULT.** structlog JSON + correlation ID + OTel + Langfuse in `core/tracing.py`. Every endpoint instrumented without opt-in.
10. **STRANGLER FIG MIGRATION.** New skeleton co-exists with old code. Old `main.py` keeps 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)
1. Fix crash β `rag_engine` re-export shim, backend healthy
2. `pyproject.toml` β uv + ruff + mypy strict + pytest
3. `.pre-commit-config.yaml` β ruff + mypy + size cap (500) + gitleaks
4. `app/core/` β 11 modules, each <200 lines
5. `app/api/v1/__init__.py` β router aggregator that still imports OLD routers (zero breakage)
6. `app/main.py` β rewritten to ~100 lines, calls lifespan + middleware from `core/`, mounts new aggregator
7. Verify: backend boots, all 757 routes respond, health 200, no import errors
8. 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.
|