KYC & User Management
This page covers user onboarding, the KYC lifecycle, session management, and role assignment — all managed via the user database service (port 8548) and the admin dashboard.
User Registration
New users register by providing email, username, and password. On creation:
- The user receives a unique UUID and an Ethereum address (either provided by the user or generated by the system using their encrypted private key).
- A Swiss-style IBAN is registered in the backend proxy's IBAN registry and linked to their Ethereum address.
kyc_statusis set topending. All trading and payment operations are blocked until KYC is approved.
Demo Seed Accounts
The user DB service seeds two pre-verified investor accounts on first startup:
| Name | Password | Role | KYC Status | Ethereum Address | IBAN | |
|---|---|---|---|---|---|---|
| Alice | alice@gmail.com | password | Trader | verified | 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 | CH5200033000000000002 |
| Bob | bob@gmail.com | password | Trader | verified | 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC | CH2500033000000000003 |
These seed accounts use well-known Anvil test private keys. Do not use them in production — the keys are publicly known and any funds sent to these addresses can be stolen.
KYC Lifecycle
Every user progresses through a defined KYC state machine. The state is stored in the user database and enforced at the frontend layer before any on-chain action is allowed.
| Status | Description | User Can... |
|---|---|---|
pending | Registered, no document submitted | View app; cannot trade, pay, or swap |
submitted | Document uploaded, awaiting admin review | View app; cannot trade, pay, or swap |
verified | Admin has approved the KYC submission | Full access to trading, payments, and swaps |
rejected | Admin has rejected the submission | View rejection reason; re-submit documents |
KYC Gate Enforcement
The frontend checks kyc_status from the session token on every protected route. A user with kyc_status != "verified" sees a banner explaining their status and a link to submit or re-submit their documents. All portfolio, payment, and swap action buttons are disabled.
Admin KYC Review
Admins review pending KYC submissions via the dashboard at http://localhost:3000/kyc.
The KYC page shows:
- A list of users with
kyc_status: submitted, sorted by submission time. - The uploaded document (PDF) viewable inline.
- User details: email, username, Ethereum address, IBAN.
- Approve and Reject buttons with an optional rejection reason field.
Approvals and rejections take effect immediately — the user's next session refresh picks up the new status.
Configuring KYC Settings
KYC document requirements and approval workflow can be configured via the admin settings:
# Update KYC settings (example: require re-verification every 12 months)
PATCH http://localhost:8548/admin/settings
Content-Type: application/json
{
"kyc_expiry_days": 365,
"kyc_document_types": ["passport", "drivers_license", "national_id"]
}
User Roles
Each user is assigned exactly one role. Roles are assigned by an Admin via the dashboard or the user DB API.
| Role | Token Transfer Limit | Capabilities |
|---|---|---|
| Admin | Unlimited | Full access: user management, KYC approval, permission configuration, all chain operations |
| Trader | ≤ $1,000,000 per transfer | Subscribe/redeem MMF shares, send IBAN payments, swap assets |
| SeniorTrader | ≤ $5,000,000 per transfer | All Trader actions at higher limits |
| Compliance | Read-only | Read all transactions and positions; configure compliance rules; freeze/unfreeze wallets |
| Auditor | Read-only | Access to transactions and audit logs only |
| Regulator | Read-only | Access to selective disclosure endpoints and regulatory reports |
Transfer limits are enforced by the PermissionRegistry contract via the backend proxy. See Permission Rules for the full rule format and how to customize limits.
Changing a User's Role
Via the dashboard (Users page):
- Find the user in the user list.
- Click the role badge to open the role editor.
- Select the new role and confirm.
Via the API:
PATCH http://localhost:8548/admin/users/{user_id}
Content-Type: application/json
{ "role": "SeniorTrader" }
Session Management
Sliding Window Sessions
Sessions use a sliding window model. Each authenticated call to GET /auth/me extends the session by the configured TTL (default: 30 minutes). A user who stays active never gets logged out. A user who goes idle for longer than the TTL is automatically logged out on their next action.
| Parameter | Default | Configurable |
|---|---|---|
| Session TTL | 30 minutes | Yes — via PATCH /admin/settings |
| Session cache in proxy | 5 seconds | Via SESSION_CACHE_TTL env var |
| Session storage | localStorage (token + expiry) | — |
Session Cache
The backend proxy caches validated session tokens for 5 seconds to avoid a user DB round-trip on every RPC call. The cache key is SHA-256(token) — the raw token is never cached or logged.
Client → backend (8546)
│
├─ Cache hit (< 5s old) → use cached role profile
└─ Cache miss → GET user_db/auth/me → cache result for 5s
This means:
- In
AUTH_MODE=advisory(default): all RPC calls are forwarded; caller identity is logged from the cache. - In
AUTH_MODE=strict: calls with no valid session token are rejected with HTTP 401.
Configuring Session Timeout
PATCH http://localhost:8548/admin/settings
Content-Type: application/json
{ "session_timeout_minutes": 60 }
Changes take effect for new sessions immediately. Existing sessions retain their original TTL until they are next refreshed.
User DB API Reference
The user DB service exposes a REST API at port 8548. These endpoints are consumed by the dashboard and investor frontends — they are not part of the JSON-RPC interface.
Authentication
POST /auth/login
Authenticate a user and return a session token.
Request:
{
"email": "alice@example.com",
"password": "password"
}
Response:
{
"token": "eyJ...",
"expires_at": "2026-04-13T10:30:00Z"
}
GET /auth/me
Validate the current session token and return the user profile. Extends the session TTL.
Headers: Authorization: Bearer <token>
Response:
{
"user_id": "uuid",
"email": "alice@example.com",
"username": "alice",
"ethereum_address": "0x70997970...",
"role": "Trader",
"kyc_status": "verified",
"iban": "CH5200033000000000002",
"expires_at": "2026-04-13T10:30:00Z"
}
User Management (Admin Only)
GET /admin/users
List all registered users.
PATCH /admin/users/{user_id}
Update a user's role or KYC status.
Request: { "role": "SeniorTrader" } or { "kyc_status": "verified" }
DELETE /admin/users/{user_id}
Remove a user account. Does not affect on-chain state.
KYC
POST /kyc/submit
Upload a KYC document (PDF). Sets kyc_status to submitted.
Request: multipart/form-data with file field.
GET /admin/kyc/pending
List users with kyc_status: submitted, ordered by submission time.
POST /admin/kyc/{user_id}/approve
Approve a KYC submission. Sets kyc_status to verified.
POST /admin/kyc/{user_id}/reject
Reject a KYC submission. Optionally include a reason in the request body.
Settings
GET /admin/settings
Return current settings (session timeout, KYC configuration).
PATCH /admin/settings
Update one or more settings. Accepts session_timeout_minutes, kyc_expiry_days, kyc_document_types.