Corrections per 2026-04 institutional review:
- MLFO reclassified as Global Family Office (was incorrectly labeled central bank)
- BIS Innovation Hub reclassified as Standards Body (does not hold observer seat)
- Added missing entities: ICCC, SAID, PANDA, Order of Hospitallers (XOM)
- Added BRICS founding + expanded member central banks (10 entries)
New institutional tier taxonomy (7 tiers):
sovereign_central_bank, global_family_office, settlement_member,
infrastructure_operator, oversight_judicial, delegated_authority,
standards_body
Backend changes:
- New auth/membership.go: tier types, DefaultTrackForTier mapping,
MembershipStore with DB queries for member directory
- New migration 0017: institutional_members + institutional_member_wallets
tables with seed data for all corrected members
- Updated wallet_auth.go getUserTrack(): now resolves institutional
membership (via wallet junction table) before defaulting to Track 1
- WalletAuthResponse now includes institutional_tier and institution_name
- New REST endpoints: GET /api/v1/membership/{tiers,members,members/:slug}
- Added TrackLabel() helper in featureflags
Frontend changes:
- Added InstitutionalTier type and label map to access.ts
- WalletAccessSession extended with institutionalTier/institutionName
- Navbar getAccessTier() now displays institutional tier label when present
- Session summary shows institution name
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
137 lines
3.5 KiB
Go
137 lines
3.5 KiB
Go
package featureflags
|
|
|
|
// FeatureFlag represents a feature flag with track requirement
|
|
type FeatureFlag struct {
|
|
Name string
|
|
RequiredTrack int
|
|
Description string
|
|
}
|
|
|
|
// FeatureFlags maps feature names to their definitions
|
|
var FeatureFlags = map[string]FeatureFlag{
|
|
"address_full_detail": {
|
|
Name: "address_full_detail",
|
|
RequiredTrack: 2,
|
|
Description: "Full address detail pages with transaction history",
|
|
},
|
|
"token_balances": {
|
|
Name: "token_balances",
|
|
RequiredTrack: 2,
|
|
Description: "View token balances for addresses",
|
|
},
|
|
"tx_history": {
|
|
Name: "tx_history",
|
|
RequiredTrack: 2,
|
|
Description: "Transaction history pagination",
|
|
},
|
|
"internal_txs": {
|
|
Name: "internal_txs",
|
|
RequiredTrack: 2,
|
|
Description: "Internal transaction tracking",
|
|
},
|
|
"enhanced_search": {
|
|
Name: "enhanced_search",
|
|
RequiredTrack: 2,
|
|
Description: "Enhanced search with token support",
|
|
},
|
|
"analytics_dashboard": {
|
|
Name: "analytics_dashboard",
|
|
RequiredTrack: 3,
|
|
Description: "Analytics dashboard access",
|
|
},
|
|
"flow_tracking": {
|
|
Name: "flow_tracking",
|
|
RequiredTrack: 3,
|
|
Description: "Address-to-address flow tracking",
|
|
},
|
|
"bridge_analytics": {
|
|
Name: "bridge_analytics",
|
|
RequiredTrack: 3,
|
|
Description: "Bridge analytics and flow history",
|
|
},
|
|
"token_distribution": {
|
|
Name: "token_distribution",
|
|
RequiredTrack: 3,
|
|
Description: "Token concentration and distribution analysis",
|
|
},
|
|
"address_risk": {
|
|
Name: "address_risk",
|
|
RequiredTrack: 3,
|
|
Description: "Address risk analysis",
|
|
},
|
|
"operator_panel": {
|
|
Name: "operator_panel",
|
|
RequiredTrack: 4,
|
|
Description: "Operator control panel access",
|
|
},
|
|
"validator_status": {
|
|
Name: "validator_status",
|
|
RequiredTrack: 4,
|
|
Description: "Validator/sequencer status views",
|
|
},
|
|
"protocol_config": {
|
|
Name: "protocol_config",
|
|
RequiredTrack: 4,
|
|
Description: "Protocol configuration visibility",
|
|
},
|
|
"bridge_control": {
|
|
Name: "bridge_control",
|
|
RequiredTrack: 4,
|
|
Description: "Bridge control operations",
|
|
},
|
|
}
|
|
|
|
// HasAccess checks if a user's track level has access to a required track
|
|
func HasAccess(userTrack int, requiredTrack int) bool {
|
|
return userTrack >= requiredTrack
|
|
}
|
|
|
|
// IsFeatureEnabled checks if a feature is enabled for a user's track level
|
|
func IsFeatureEnabled(featureName string, userTrack int) bool {
|
|
feature, exists := FeatureFlags[featureName]
|
|
if !exists {
|
|
return false
|
|
}
|
|
return HasAccess(userTrack, feature.RequiredTrack)
|
|
}
|
|
|
|
// GetEnabledFeatures returns a map of all features and their enabled status for a track
|
|
func GetEnabledFeatures(userTrack int) map[string]bool {
|
|
features := make(map[string]bool)
|
|
for name, feature := range FeatureFlags {
|
|
features[name] = HasAccess(userTrack, feature.RequiredTrack)
|
|
}
|
|
return features
|
|
}
|
|
|
|
// GetRequiredTrack returns the required track level for a feature
|
|
func GetRequiredTrack(featureName string) (int, bool) {
|
|
feature, exists := FeatureFlags[featureName]
|
|
if !exists {
|
|
return 0, false
|
|
}
|
|
return feature.RequiredTrack, true
|
|
}
|
|
|
|
// GetAllFeatures returns all feature flags
|
|
func GetAllFeatures() map[string]FeatureFlag {
|
|
return FeatureFlags
|
|
}
|
|
|
|
// TrackLabel returns a human-readable label for an access track number.
|
|
func TrackLabel(track int) string {
|
|
switch track {
|
|
case 1:
|
|
return "Explorer"
|
|
case 2:
|
|
return "Enhanced Explorer"
|
|
case 3:
|
|
return "Analytics"
|
|
case 4:
|
|
return "Operator"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|