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>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import Link from 'next/link'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { type ReactNode, useEffect, useId, useMemo, useRef, useState } from 'react'
|
||||
import { accessApi, type WalletAccessSession } from '@/services/api/access'
|
||||
import { accessApi, institutionalTierLabels, type WalletAccessSession } from '@/services/api/access'
|
||||
import BrandLockup from './BrandLockup'
|
||||
import HeaderCommandPalette, { type HeaderCommandItem } from './HeaderCommandPalette'
|
||||
import { useUiMode } from './UiModeContext'
|
||||
@@ -310,6 +310,9 @@ function SearchControl({
|
||||
}
|
||||
|
||||
function getAccessTier(walletSession: WalletAccessSession) {
|
||||
if (walletSession.institutionalTier) {
|
||||
return institutionalTierLabels[walletSession.institutionalTier] ?? walletSession.institutionalTier
|
||||
}
|
||||
const permissions = walletSession.permissions || []
|
||||
if (permissions.some((permission) => permission.startsWith('operator.'))) {
|
||||
return 'Operator Tier'
|
||||
@@ -326,10 +329,11 @@ function getAccessTier(walletSession: WalletAccessSession) {
|
||||
function getSessionSummary(walletSession: WalletAccessSession) {
|
||||
const permissionCount = walletSession.permissions?.length || 0
|
||||
const tierLabel = getAccessTier(walletSession)
|
||||
const institutionSuffix = walletSession.institutionName ? ` (${walletSession.institutionName})` : ''
|
||||
if (permissionCount > 0) {
|
||||
return `${tierLabel} · ${permissionCount} permission${permissionCount === 1 ? '' : 's'}`
|
||||
return `${tierLabel}${institutionSuffix} · ${permissionCount} permission${permissionCount === 1 ? '' : 's'}`
|
||||
}
|
||||
return `${tierLabel} · Explorer access active`
|
||||
return `${tierLabel}${institutionSuffix} · Explorer access active`
|
||||
}
|
||||
|
||||
function UiModeToggle({ mobile = false }: { mobile?: boolean }) {
|
||||
|
||||
@@ -21,12 +21,33 @@ export interface AccessSession {
|
||||
expires_at: string
|
||||
}
|
||||
|
||||
export type InstitutionalTier =
|
||||
| 'sovereign_central_bank'
|
||||
| 'global_family_office'
|
||||
| 'settlement_member'
|
||||
| 'infrastructure_operator'
|
||||
| 'oversight_judicial'
|
||||
| 'delegated_authority'
|
||||
| 'standards_body'
|
||||
|
||||
export const institutionalTierLabels: Record<InstitutionalTier, string> = {
|
||||
sovereign_central_bank: 'Sovereign Central Bank',
|
||||
global_family_office: 'Global Family Office',
|
||||
settlement_member: 'Settlement Member',
|
||||
infrastructure_operator: 'Infrastructure Operator',
|
||||
oversight_judicial: 'Oversight & Judicial',
|
||||
delegated_authority: 'Delegated Authority',
|
||||
standards_body: 'Standards Body',
|
||||
}
|
||||
|
||||
export interface WalletAccessSession {
|
||||
token: string
|
||||
expiresAt: string
|
||||
track: string
|
||||
permissions: string[]
|
||||
address: string
|
||||
institutionalTier?: InstitutionalTier
|
||||
institutionName?: string
|
||||
}
|
||||
|
||||
export interface AccessProduct {
|
||||
@@ -220,6 +241,8 @@ export const accessApi = {
|
||||
expires_at: string
|
||||
track: string
|
||||
permissions: string[]
|
||||
institutional_tier?: InstitutionalTier
|
||||
institution_name?: string
|
||||
}>(`${ACCESS_API_PREFIX}/auth/wallet`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ address, signature, nonce }),
|
||||
@@ -230,6 +253,8 @@ export const accessApi = {
|
||||
track: response.track,
|
||||
permissions: response.permissions || [],
|
||||
address,
|
||||
institutionalTier: response.institutional_tier,
|
||||
institutionName: response.institution_name,
|
||||
}
|
||||
setStoredWalletSession(session)
|
||||
return session
|
||||
|
||||
Reference in New Issue
Block a user