Architecture
System topology, data flows, and integration architecture.
System Topology
Internet
┌────────────────┐ ┌─────────────────────────────┐
│ app.nautpay │ │ Coolify Proxy │
│ (Coolify) │ │ ┌──────────┐ ┌──────────┐ │
└───────┬────────┘ │ │api.nautl.│ │app.nautl.│ │
│ │ └────┬─────┘ └────┬─────┘ │
▼ │ ▼ ▼ │
┌────────────────┐ │ ┌──────────────────────┐ │
│ Next.js 14 │───────────────► │ │ NautLense Express │ │
│ (App Router) │ HTTP/JSON │ │ server.js :8090 │ │
└───────┬────────┘ │ └──────┬──────┬───────┘ │
│ │ │ │ │
┌───────▼────────┐ │ ┌──────▼──┐ ┌─▼────────┐ │
│ Solana RPC │ │ │ PG 16 │ │ Redis 7 │ │
│ (devnet) │ │ │pgvector │ │ (cache) │ │
└───────┬────────┘ │ └─────────┘ └──────────┘ │
│ └─────────────────────────────┘
┌───────▼────────┐
│ Jupiter Agg. │
│lite-api.jup.ag │
└────────────────┘NautPay Frontend
| Aspect | Detail |
|---|---|
| Framework | Next.js 14 with App Router |
| Language | TypeScript |
| Styling | Tailwind CSS with custom dark theme |
| Wallet | Solana Wallet Adapter (Phantom, Solflare) |
| NLP | Claude Haiku (Anthropic) for intent parsing |
| Build | output: 'standalone' for Docker deployment |
Server Routes
| Route | Purpose |
|---|---|
POST /api/agent | Parse NL intent, compliance pre-flight, return structured tx |
POST /api/swap | Jupiter aggregator proxy (avoids CORS) |
POST /api/wallet-verify | Proxy to NautLense wallet verification |
POST /api/kyc/sumsub-token | Sumsub WebSDK token generation (optional) |
NautLense Backend
| Aspect | Detail |
|---|---|
| Framework | Express.js |
| Language | JavaScript (CommonJS) |
| Database | PostgreSQL 16 with pgvector |
| Cache | Redis 7 (optional, graceful degradation) |
| Graph DB | Neo4j (optional) |
| Version | 0.3.0 |
Route Modules (14)
Loaded in dependency order. Later modules consume helpers from earlier ones via app._helperName:
auth -> app._requireAuth
settings -> app._getJurisdictionSettings
notifications -> app._createNotification
sanctions -> app._screenSanctions
counterparties
wallet-verification
travel-rule -> app._validateTravelRuleData
kyc
sar
emergency -> app._isLockdown, app._getLockdownState
treasury -> app._checkTreasuryPolicy
transactions (consumes all above)
reports
accountingPayment Flow
User types: "Pay 5000 USDC to Alice"
│
▼
POST /api/agent (NautPay server)
├── Pattern match intent (fast, no API call)
├── Claude Haiku fallback (if confidence < 0.9)
├── Check emergency lockdown status
├── Resolve recipient (address / .sol domain / contact)
├── POST /tx/compliance-check (NautLense pre-flight)
│ ├── Risk scoring (threshold, velocity, new wallet, round amount)
│ ├── Treasury policy check
│ └── Return: { approved, risk_score, recommendation }
│
├── If approved: return intent for client-side wallet signing
├── If flagged: return pendingTx, ask user to "confirm"
└── If blocked: return error with risk reasons
│
▼
Client signs with Phantom/Solflare
├── Build Solana transaction (SOL or SPL transfer)
├── signTransaction() -> sendRawTransaction()
└── Poll for confirmation (30s timeout)
│
▼
POST /tx/capture (NautLense, fire-and-forget)
├── Risk scoring
├── Sanctions screening (SECO/OFAC/EU/UN)
├── Travel Rule validation
├── SHA256 hash chain link
├── Wallet profile upsert
└── Notification (if high-risk)Swap Flow
User types: "Convert 1000 USDC to EURC"
│
▼
POST /api/swap { action: 'quote', inputToken, outputToken, amount }
├── Server calls lite-api.jup.ag/swap/v1/quote
└── Returns quote with price impact, route plan
│
▼
User confirms → POST /api/swap { action: 'transaction', quote, userPublicKey }
├── Server calls lite-api.jup.ag/swap/v1/swap
├── Returns serialized transaction
└── Wallet signs and broadcasts to Solana RPCOnboarding Flow
User connects wallet
│
▼
Check localStorage: isOnboardingComplete(wallet)?
├── Yes: show main chat interface
└── No: show OnboardingFlow
│
Step 1: Welcome (app intro, "Get Started")
Step 2: Wallet Verify (Poco challenge-response)
├── NautLense generates challenge message
├── User signs with Phantom (ed25519 off-chain format)
└── NautLense verifies ed25519 signature
Step 3: KYC (Sumsub or skip)
Step 4: Complete (auto-redirect to main app)SHA256 Hash Chain
Every transaction in transaction_audit contains a hash (SHA256 of the full record including prev_hash) and prev_hash (the hash of the preceding record). This creates an immutable, tamper-evident chain. GET /tx/verify-chain walks the entire chain and reports any breaks.