Files
explorer-monorepo/docs/ARCHITECTURE.md

163 lines
5.0 KiB
Markdown
Raw Normal View History

docs: rewrite README (<=100 lines), add ARCHITECTURE.md with Mermaid diagrams, add API.md from swagger.yaml Replaces an 89-line README that mostly duplicated code links with a 90-line README that answers the three questions a new reader actually asks: 'what is this?', 'how do I run it?', 'where do I go next?'. Also adds two longer-form references that the old README was missing entirely: docs/ARCHITECTURE.md (new): - Four Mermaid diagrams: 1. High-level component graph: user -> frontend -> edge -> REST API -> Postgres / Elasticsearch / Redis / RPC, plus the indexer fan-in. 2. Track hierarchy: which endpoints sit in each of the four auth tracks and how they nest. 3. Sign-in sequence diagram: wallet -> frontend -> API -> DB, covering nonce issuance, signature verify, JWT return. 4. Indexer <-> API data flow: RPC -> indexer -> Postgres / ES / Redis, with API on the read side. - Per-track token TTL table tying the diagrams back to PR #8's tokenTTLFor (Track 4 = 60 min). - Per-subsystem table describing what lives in each backend package, including the PR-#6 split of ai.go into six files. - Runtime dependencies table. - Security posture summary referencing PR #3's fail-fast JWT / CSP checks, .gitleaks.toml, and docs/SECURITY.md. docs/API.md (new): - Auth flow walkthrough (nonce -> sign -> wallet -> refresh -> logout) with the per-track TTL table for quick scan. - Rate-limit matrix. - Tagged endpoint index generated from backend/api/rest/swagger.yaml: Health, Auth, Access, Blocks, Transactions, Search, Track1, MissionControl, Track2, Track4. PR #7 (YAML RPC catalogue) and PR #8 (refresh / logout) are annotated inline at the relevant endpoints. - Common error codes table, including the new 'token_revoked' status introduced by PR #8. - Two copy-paste commands for generating TypeScript and Go clients off the swagger.yaml, so downstream repos don't have to hand-maintain one. README.md: - Trimmed to 90 lines (previous was 89 lines of README lore). - Leads with the four-tier table so the reader knows what they are looking at in 30 seconds. - 'Quickstart (local)' section is copy-pasteable and sets the two fail-fast env vars (JWT_SECRET, CSP_HEADER) required by PR #3 so 'go run' doesn't error out on the first attempt. - Forward-references docs/ARCHITECTURE.md, docs/API.md, docs/TESTING.md (from PR #10), docs/SECURITY.md (from PR #3), and CONTRIBUTING.md. - Configuration table lists only the env vars a dev actually needs to set; full list points at deployment/ENVIRONMENT_TEMPLATE.env. Verification: wc -l README.md = 93 (target was <=150). wc -l docs/ARCHITECTURE.md = 145 (four diagrams, tables, pointers). wc -l docs/API.md = 115 (index + auth/error tables). markdownlint-style scan no obvious issues. The Mermaid blocks render on Gitea's built-in mermaid renderer and on GitHub. Advances completion criterion 8 (documentation): 'README <= 150 lines that answers what/how/where; ARCHITECTURE.md with diagrams of tracks, components, and data flow; API.md generated from swagger.yaml. Old ~300 status markdown files were removed by PR #2.'
2026-04-18 19:29:36 +00:00
# Architecture
## Overview
SolaceScan is a four-tier block explorer + access-control plane for
Chain 138. Every request is classified into one of four **tracks**;
higher tracks require stronger authentication and hit different
internal subsystems.
```mermaid
flowchart LR
U[User / wallet / operator] -->|HTTPS| FE[Next.js frontend<br/>:3000]
U -->|direct API<br/>or SDK| EDGE[Edge / nginx<br/>:443]
FE --> EDGE
EDGE --> API[Go REST API<br/>backend/api/rest :8080]
API --> PG[(Postgres +<br/>TimescaleDB)]
API --> ES[(Elasticsearch)]
API --> RD[(Redis)]
API --> RPC[(Chain 138 RPC<br/>core / alltra / thirdweb)]
IDX[Indexer<br/>backend/indexer] --> PG
IDX --> ES
RPC --> IDX
subgraph Access layer
EDGE -->|auth_request| VK[validate-key<br/>/api/v1/access/internal/validate-key]
VK --> API
end
```
## Tracks
```mermaid
flowchart TB
subgraph Track1[Track 1 — public, no auth]
T1A[/blocks]
T1B[/transactions]
T1C[/search]
T1D[/api/v1/track1/*]
end
subgraph Track2[Track 2 — wallet-verified]
T2A[Subscriptions]
T2B[API key lifecycle]
T2C[Usage + audit self-view]
end
subgraph Track3[Track 3 — analytics]
T3A[Advanced analytics]
T3B[Admin audit]
T3C[Admin subscription review]
end
subgraph Track4[Track 4 — operator]
T4A[/api/v1/track4/operator/run-script]
T4B[Mission-control SSE]
T4C[Ops tooling]
end
Track1 --> Track2 --> Track3 --> Track4
```
Authentication for tracks 24 is SIWE-style: client hits
`/api/v1/auth/nonce`, signs the nonce with its wallet, posts the
signature to `/api/v1/auth/wallet`, gets a JWT back. JWTs carry the
resolved `track` claim and a `jti` for server-side revocation (see
`backend/auth/wallet_auth.go`).
### Per-track token TTLs
| Track | TTL | Rationale |
|------|-----|-----------|
| 1 | 12h | Public / long-lived session OK |
| 2 | 8h | Business day |
| 3 | 4h | Analytics session |
| 4 | **60 min** | Operator tokens are the most dangerous; short TTL + `POST /api/v1/auth/refresh` |
Revocation lives in `jwt_revocations` (migration `0016`). Logging out
(`POST /api/v1/auth/logout`) inserts the token's `jti` so subsequent
validation rejects it.
## Sign-in flow (wallet)
```mermaid
sequenceDiagram
autonumber
actor W as Wallet
participant FE as Frontend
participant API as REST API
participant DB as Postgres
W->>FE: connect / sign-in
FE->>API: POST /api/v1/auth/nonce {address}
API->>DB: insert wallet_nonces(address, nonce, expires_at)
API-->>FE: {nonce}
FE->>W: signTypedData/personal_sign(nonce)
W-->>FE: signature
FE->>API: POST /api/v1/auth/wallet {address, nonce, signature}
API->>API: ecrecover → verify address
API->>DB: consume nonce; resolve user track
API-->>FE: {token, expiresAt, track, permissions}
FE-->>W: session active
```
## Data flow (indexer ↔ API)
```mermaid
flowchart LR
RPC[(Chain 138 RPC)] -->|new blocks| IDX[Indexer]
IDX -->|INSERT blocks, txs, logs| PG[(Postgres)]
IDX -->|bulk index| ES[(Elasticsearch)]
IDX -->|invalidate| RD[(Redis)]
API[REST API] -->|SELECT| PG
API -->|search, facets| ES
API -->|cached RPC proxy| RD
API -->|passthrough for deep reads| RPC
```
## Subsystems
- **`backend/api/rest`** — HTTP API. One package; every handler lives
under `backend/api/rest/*.go`. AI endpoints were split into
`ai.go` + `ai_context.go` + `ai_routes.go` + `ai_docs.go` +
`ai_xai.go` + `ai_helpers.go` by PR #6 to keep file size
manageable.
- **`backend/auth`** — wallet auth (nonce issue, signature verify,
JWT issuance / validation / revocation / refresh).
- **`backend/indexer`** — Chain 138 block/tx/log indexer, writes
Postgres + Elasticsearch, invalidates Redis.
- **`backend/analytics`** — longer-running queries: token distribution,
holder concentration, liquidity-pool aggregates.
- **`backend/api/track4`** — operator-scoped endpoints
(`run-script`, mission-control).
- **`frontend`** — Next.js 14 pages-router app. Router decision
(PR #9) is final: no `src/app/`.
## Runtime dependencies
| Service | Why |
|---------|-----|
| Postgres (+ TimescaleDB) | Chain data, users, subscriptions, `jwt_revocations` |
| Elasticsearch | Full-text search, facets |
| Redis | Response cache, rate-limit counters, SSE fan-out |
| Chain 138 RPC | Upstream source of truth; three lanes — core / alltra / thirdweb — catalogued in `backend/config/rpc_products.yaml` |
## Deployment
See [deployment/README.md](../deployment/README.md) for compose and
production deploy details. The `deployment/docker-compose.yml` file
is the reference local stack and is what `make e2e-full` drives.
## Security posture
- `JWT_SECRET` and `CSP_HEADER` are **fail-fast** — a production
binary refuses to start without them (PR #3).
- Secrets never live in-repo; `.gitleaks.toml` blocks known-bad
patterns at commit time.
- Rotation checklist: [docs/SECURITY.md](SECURITY.md).
- Track-4 token TTL capped at 60 min; every issued token is
revocable by `jti`.