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.