feat: add admin panel with multi-chain support and notification system

- Add full admin REST API: auth, API keys, chains, chain tokens, wallets,
  orders, RPC nodes, settings, dashboard stats, notifications
- Add JWT-based admin authentication and API key auth middleware
- Add multi-chain listeners: BSC, ETH, Polygon, Plasma, EVM WebSocket
- Add RPC node health check job with automatic failover
- Add Telegram notification channel for order events
- Add installer for first-run database initialization
- Add new DB models: admin_user, api_key, chain, chain_token,
  rpc_node, settings, notification_channel
- Add order statistics aggregation (daily/monthly/by-chain)
- Serve built admin SPA from embedded www/ assets
- Add comprehensive test coverage for all new features
This commit is contained in:
line-6000
2026-04-22 02:28:31 +08:00
parent 097c716714
commit 6bb47d4b00
247 changed files with 9933 additions and 1279 deletions
+54
View File
@@ -0,0 +1,54 @@
package data
import (
"strings"
"github.com/assimon/luuu/model/dao"
"github.com/assimon/luuu/model/mdb"
)
// ListChains returns all chain rows ordered by id.
func ListChains() ([]mdb.Chain, error) {
var rows []mdb.Chain
err := dao.Mdb.Model(&mdb.Chain{}).Order("id ASC").Find(&rows).Error
return rows, err
}
// ListEnabledChains returns only rows with Enabled=true.
func ListEnabledChains() ([]mdb.Chain, error) {
var rows []mdb.Chain
err := dao.Mdb.Model(&mdb.Chain{}).
Where("enabled = ?", true).
Order("id ASC").Find(&rows).Error
return rows, err
}
// GetChainByNetwork fetches one row by network key.
func GetChainByNetwork(network string) (*mdb.Chain, error) {
row := new(mdb.Chain)
err := dao.Mdb.Model(row).
Where("network = ?", strings.ToLower(strings.TrimSpace(network))).
Limit(1).Find(row).Error
return row, err
}
// IsChainEnabled returns whether the row exists and Enabled=true. A
// missing row is treated as disabled — scanners must be able to
// short-circuit even before the admin creates the chain entry.
func IsChainEnabled(network string) bool {
row, err := GetChainByNetwork(network)
if err != nil || row.ID == 0 {
return false
}
return row.Enabled
}
// UpdateChainFields patches mutable columns.
func UpdateChainFields(network string, fields map[string]interface{}) error {
if len(fields) == 0 {
return nil
}
return dao.Mdb.Model(&mdb.Chain{}).
Where("network = ?", strings.ToLower(strings.TrimSpace(network))).
Updates(fields).Error
}