Crypto Exchange Admin Panel Development
An exchange's administrative panel is the operational center for management. Operators monitor trading, support team handles tickets, compliance officer checks suspicious transactions, finance team manages reserves. One tool for everything means proper role system and clear access separation.
Role Architecture and Permissions
RBAC (Role-Based Access Control)
type Permission string
const (
// Users
ViewUsers Permission = "users:view"
EditUsers Permission = "users:edit"
FreezeUsers Permission = "users:freeze"
// KYC/AML
ViewKYC Permission = "kyc:view"
ApproveKYC Permission = "kyc:approve"
ViewAML Permission = "aml:view"
ManageAML Permission = "aml:manage"
// Trading
ViewOrders Permission = "orders:view"
CancelOrders Permission = "orders:cancel"
// Finance
ViewBalances Permission = "finance:view"
ViewWithdrawals Permission = "finance:withdrawals:view"
ApproveWithdrawals Permission = "finance:withdrawals:approve"
// System
ViewSystemMetrics Permission = "system:metrics"
ManageConfig Permission = "system:config"
ManageTradingPairs Permission = "markets:manage"
)
type Role struct {
Name string
Permissions []Permission
}
var Roles = map[string]Role{
"super_admin": {
Name: "Super Admin",
Permissions: AllPermissions,
},
"compliance": {
Name: "Compliance Officer",
Permissions: []Permission{
ViewUsers, ViewKYC, ApproveKYC, ViewAML, ManageAML,
ViewOrders, ViewBalances, ViewWithdrawals,
},
},
"support": {
Name: "Support Agent",
Permissions: []Permission{
ViewUsers, ViewOrders, ViewKYC,
},
},
"finance": {
Name: "Finance",
Permissions: []Permission{
ViewBalances, ViewWithdrawals, ApproveWithdrawals,
},
},
"marketing": {
Name: "Marketing",
Permissions: []Permission{
ViewUsers, // read-only analytics
},
},
}
Key Admin Panel Modules
Dashboard — Main Screen
interface DashboardMetrics {
// Trading
volume24h: string;
trades24h: number;
activeUsers24h: number;
// Finance
totalDeposits24h: string;
totalWithdrawals24h: string;
pendingWithdrawals: number;
pendingWithdrawalsUSD: string;
// KYC
pendingKYCApprovals: number;
// System
matchingEngineLatency: number; // ms
wsConnections: number;
apiRps: number;
// Alerts
activeAlerts: SystemAlert[];
}
function AdminDashboard() {
const { data } = useQuery('dashboard-metrics', fetchMetrics, {
refetchInterval: 30000, // refresh every 30 sec
});
return (
<Grid>
<MetricCard title="24h Volume" value={data?.volume24h} trend={data?.volumeTrend} />
<MetricCard title="Pending Withdrawals" value={data?.pendingWithdrawalsUSD}
alert={data?.pendingWithdrawals > 50} />
<MetricCard title="KYC Queue" value={data?.pendingKYCApprovals} />
<ActiveAlerts alerts={data?.activeAlerts} />
<RecentTradesTable />
<SystemHealthIndicators />
</Grid>
);
}
User Management
function UserManagement() {
const [filters, setFilters] = useState({
search: '',
kycStatus: 'all',
frozen: false,
country: '',
});
return (
<div>
<UserFilters filters={filters} onChange={setFilters} />
<DataTable
columns={[
{ key: 'id', label: 'ID' },
{ key: 'email', label: 'Email' },
{ key: 'fullName', label: 'Name' },
{ key: 'kycTier', label: 'KYC Tier', render: (v) => <KYCBadge tier={v} /> },
{ key: 'registeredAt', label: 'Registered', render: (v) => formatDate(v) },
{ key: 'volume30d', label: '30d Volume' },
{ key: 'status', render: (_, row) => <UserStatusActions user={row} /> },
]}
fetchData={(params) => fetchUsers({ ...params, ...filters })}
onRowClick={(user) => openUserDetail(user.id)}
/>
</div>
);
}
function UserDetail({ userId }: { userId: number }) {
const { data: user } = useQuery(['user', userId], () => fetchUser(userId));
return (
<Tabs>
<Tab label="Overview">
<UserInfo user={user} />
<BalanceSummary userId={userId} />
</Tab>
<Tab label="KYC Documents">
<KYCDocumentViewer userId={userId} />
<KYCApprovalActions userId={userId} />
</Tab>
<Tab label="Orders">
<OrderHistory userId={userId} />
</Tab>
<Tab label="Transactions">
<TransactionHistory userId={userId} />
</Tab>
<Tab label="Activity Log">
<UserActivityLog userId={userId} />
</Tab>
<Tab label="Actions">
<FreezeAccount userId={userId} />
<AdjustBalance userId={userId} />
<AddKYCNote userId={userId} />
</Tab>
</Tabs>
);
}
Withdrawal Management
Large withdrawals require manual approval. Interface for compliance/finance team:
function WithdrawalQueue() {
const { data: withdrawals } = useQuery('pending-withdrawals', fetchPendingWithdrawals);
return (
<div>
<StatsBar
total={withdrawals?.total}
totalUSD={withdrawals?.totalUSD}
flagged={withdrawals?.flaggedCount}
/>
{withdrawals?.items.map(w => (
<WithdrawalCard key={w.id} withdrawal={w}>
<UserRiskIndicator userId={w.userId} />
<AMLCheckResult withdrawalId={w.id} />
<BlockchainAddressInfo address={w.address} />
<ActionButtons>
<ApproveButton withdrawalId={w.id} requiresReason={w.amount > 10000} />
<RejectButton withdrawalId={w.id} />
<FlagForReviewButton withdrawalId={w.id} />
</ActionButtons>
</WithdrawalCard>
))}
</div>
);
}
Admin Panel Security
2FA Required for All Operators
function RequireRecentMFA({ children }: { children: React.ReactNode }) {
const { lastMFAAt } = useAdminSession();
const isRecent = lastMFAAt && Date.now() - lastMFAAt < 30 * 60 * 1000; // 30 minutes
if (!isRecent) {
return <MFAChallengeModal onSuccess={refreshSession} />;
}
return <>{children}</>;
}
Admin Audit Log
Every operator action is logged:
type AdminAuditEntry struct {
AdminID int64
AdminEmail string
Action string // "approve_withdrawal", "freeze_user", "update_config"
EntityType string // "withdrawal", "user", "trading_pair"
EntityID string
Before string // JSON state before change
After string // JSON state after
IPAddress string
CreatedAt time.Time
}
IP Restriction
Admin panel accessible only from corporate VPN or fixed IPs.
Tech Stack
| Component | Technology |
|---|---|
| Frontend | React + TypeScript + TanStack Query |
| UI Kit | Shadcn/ui + Tailwind |
| Charts | Recharts / TradingView Lightweight |
| Realtime | WebSocket + Zustand |
| Backend | Go REST API |
| Auth | JWT + TOTP 2FA |
| RBAC | Custom middleware |
| Audit | PostgreSQL + immutable log |
Development Timeline
| Module | Timeline |
|---|---|
| Authentication + RBAC | 2–3 weeks |
| Dashboard with metrics | 2–3 weeks |
| User management | 3–4 weeks |
| KYC approval workflow | 2–3 weeks |
| Withdrawal queue | 2–3 weeks |
| Market management | 2–3 weeks |
| System monitoring | 2–3 weeks |
| Audit log | 1–2 weeks |
Full administrative panel: 3–4 months.







