Status: ✅ Implemented
Files Created/Modified:
lib/auth/config.ts- NextAuth configuration with role-based session handlingapp/api/auth/[...nextauth]/route.ts- NextAuth API route handlerprisma/schema.prisma- AddedsuspendedAtandsuspensionReasonto User modelprisma/migrations/20260626_add_user_suspension_tracking/migration.sql- DB migrationapp/admin/actions.ts- Server actions for: changeUserRole, suspendUser, unsuspendUser, deleteUserapp/admin/users/page.tsx- Integrated real database queries, added loading states
Completed Features:
- ✅ Searchable/filterable user table with pagination
- ✅ Role change dropdown (with ADMIN elevation confirmation)
- ✅ Self-promotion prevention (admin cannot self-promote)
- ✅ Ban/unban with required reason
- ✅ Session revocation on ban (deletes all sessions)
- ✅ Audit logging for all actions
- ✅ Bulk suspend/delete operations
4-Eyes Principle Implementation:
- Currently uses confirmation dialog before ADMIN elevation
- Enhanced implementation option: Add
AdminApprovalRequestmodel to store pending approvals and require second admin confirmation before applying
Status: 🟡 Partially Implemented - Core integration structure complete, STT library integration pending
Files Created/Modified:
mobile/src/hooks/useStreamSubtitles.ts- Hook for managing subtitle state and translationmobile/src/components/streaming/StreamViewerScreen.tsx- Integrated subtitle display and CC button
Completed Features:
- ✅ CC toggle button with accessibility attributes
- ✅ Subtitle overlay at bottom of viewer
- ✅ Real-time subtitle buffering (3-second chunks)
- ✅ Integration with useChatTranslation for multi-language support
- ✅ Partial vs final transcription handling
Pending Implementation:
- ⏳ STT Library Integration: Need to add and integrate one of:
expo-speech(built-in iOS/Android support)@react-native-community/voice(more flexible)- Or custom backend STT service integration
Integration Steps:
- Install chosen STT library:
npm install expo-speech(or alternative) - Implement
processAudioChunkcall in StreamViewerScreen when audio frame available - Connect to stream's audio track for real-time transcription
- Set default latency target to <3s for good UX
Language Support:
- Framework in place via
useChatTranslation - Auto-detect language and translate subtitles
- Supports: Spanish (es), French (fr), German (de), Arabic (ar)
Status: 🔴 Not Yet Implemented
Required Implementation:
#[derive(Clone, Copy)]
pub enum EscrowError {
Unauthorized = 1,
InvalidEscrow = 2,
InvalidStatus = 3,
SlippageExceeded = 4, // New error variant
}
impl From<EscrowError> for Result<(), EscrowError> {
fn from(e: EscrowError) -> Self {
Err(e)
}
}pub fn deposit_to_yield(
env: Env,
escrow_id: u64,
amount: i128,
min_shares: i128,
) -> i128 {
// 1. Verify escrow exists and is active
// 2. Call yield protocol deposit
// 3. Check shares >= min_shares
// 4. If shares < min_shares, panic_with_error!(&env, EscrowError::SlippageExceeded)
// 5. Store shares and return
}- Default max slippage: 1% (100 basis points)
- Make it governance-configurable via
configure_slippage()function - Store in YieldConfig with field:
max_slippage_bps: u32
- Add slippage tolerance control to yield deposit UI
- Show expected shares vs actual shares before depositing
- Calculate recommended min_shares = expected_shares * (1 - max_slippage_bps / 10_000)
Tests Required:
- Normal deposit passes when slippage within tolerance
- Deposit reverts with SlippageExceeded when shares < min_shares
- Edge case: exact slippage boundary
- Configuration update works correctly
Status: 🔴 Not Yet Implemented
Required Implementation:
model KYCSubmission {
id String @id @default(cuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
// Document metadata
documentType String // "passport", "driver_license", "national_id"
uploadedAt DateTime @default(now())
expiresAt DateTime @default(now() + 90 days)
// Encrypted extracted data
encryptedName String // Encrypted with AWS KMS
encryptedDOB String
encryptedIdNumber String
// Verification flow
status String @default("pending") // "pending", "approved", "rejected"
adminReviewedBy String?
adminReviewedAt DateTime?
rejectionReason String?
// On-chain verification
verifiedOnChain Boolean @default(false)
txHash String? @unique
@@index([userId])
@@index([status])
@@index([expiresAt])
}Create mobile/src/services/OCRKYCService.ts with:
uploadDocument(file, documentType)- Upload to S3extractData(imageUrl)- Call AWS Textract or Tesseract.jsencryptAndStore(extractedData)- Encrypt with AWS KMS before storingcleanupExpired()- Cron job to delete after 90 days (GDPR)
Provider Options:
- AWS Textract (Recommended): More accurate, native integration
- Tesseract.js: Open-source, runs client-side
Add to app/admin/users/page.tsx:
- KYC submissions list/tab
- Approve/Reject buttons with reason field
- Shows only extracted name (other fields stay encrypted)
- On approval: call identity contract
verify()on-chain
Call backend/contracts/identity/src/lib.rs function:
pub fn verify_kyc(env: Env, user_id: String, kyc_submission_id: String) -> bool {
// Verify KYC status in Prisma
// Mark user as verified in CreatorProfile
// Emit VerifiedKYC event
}- Encrypt at rest: AWS KMS key rotation every 90 days
- Delete after 90 days (GDPR compliance)
- Only admin can view extracted data
- Audit log every access
- No raw PII in logs/database
Tests Required:
- Document upload and processing
- OCR extraction accuracy
- Encryption/decryption
- Admin approve/reject workflow
- On-chain verify call
- Expiry cleanup task
- GDPR deletion confirmation
- Issue #784: ✅ Ready for testing - needs: unit tests for 4-eyes, self-promotion prevention
- Issue #780: 🟡 Add STT library integration (~2-3 hours)
- Issue #787: 🔴 Implement Soroban functions (~4-5 hours)
- Issue #782: 🔴 Full OCR + admin workflow (~6-8 hours)
Testing Infrastructure:
- Mobile tests: Existing test setup in
mobile/__tests__/ - Contract tests: Use soroban-sdk test utilities
- E2E: Admin pages test with mock data