Files
explorer-monorepo/backend/featureflags/flags.go
Devin AI 55a209646a feat: add institutional membership tiers and correct member directory
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>
2026-05-09 20:32:06 +00:00

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"
}
}