feat: implement feature flags module (closes #433)#1
Open
dreamgenies wants to merge 197 commits intomainfrom
Open
feat: implement feature flags module (closes #433)#1dreamgenies wants to merge 197 commits intomainfrom
dreamgenies wants to merge 197 commits intomainfrom
Conversation
## Summary Full implementation of the Badge and Achievement system with 7 badge definitions, event-driven award triggers, display selection, real-time in-app notifications, and comprehensive tests. Entities: - Badge: key (enum), name, description, iconUrl, tier (BRONZE/SILVER/ GOLD/PLATINUM), criteria (JSONB with documented fields), timestamps. - UserBadge: immutable award record per user per badge, isDisplayed flag (max 3 per user), awardedAt. Unique constraint prevents duplicates. Badge definitions (seeded on startup via OnApplicationBootstrap): - FIRST_TRANSFER (BRONZE) - complete 1 outgoing transfer - TOP_REFERRER (GOLD) - refer >= 5 users - CHAT_CHAMPION (SILVER) - send >= 100 messages - DAO_VOTER (SILVER) - cast >= 1 DAO governance vote - EARLY_ADOPTER (GOLD) - register before 2025-01-01 - CRYPTO_WHALE (PLATINUM)- single transfer >= 10,000 tokens - GROUP_FOUNDER (BRONZE) - create >= 1 group chat Database: - Migration 1736000000000-BadgesSchema creates badges and user_badges tables, badge_tier_enum, badge_key_enum, FK with CASCADE delete, and indexes on key and userId. Repositories: - BadgeRepository: findAll, findByKey, findById, upsert (for seeding). - UserBadgeRepository: award (idempotent - returns null if already awarded), findByUser, findByUserAndBadge, countDisplayed, updateDisplayed (clears all then sets selected). Service (BadgesService): - seed(): upserts all 7 definitions on bootstrap. - findAll(): returns all badge DTOs. - findForUser(userId): returns user's earned badges. - awardBadge(userId, key): idempotent award + in-app notification. - updateDisplayedBadges(userId, badgeIds): validates ownership, enforces max-3 limit, updates display flags. - Event triggers: onTransferCompleted, onReferralCompleted, onMessageSent, onDaoVoteCast, onGroupCreated, onUserRegistered - call awardBadge with the appropriate threshold checks. Controller (GET|PUT /api/badges/*): - GET /badges - all badges (public) - GET /badges/users/:userId - user badges (public) - PUT /badges/display - update displayed badges (authenticated) Notifications: - In-app notification fired on every new badge award via NotificationsService.createNotification (fire-and-forget). Tests: - badges.service.spec.ts: 20 unit tests covering findAll, findForUser, awardBadge (award/already-awarded/key-not-found), updateDisplayedBadges (success/too-many/not-owned), and all 7 event trigger methods. - user-badge.repository.spec.ts: 5 unit tests covering idempotent award, new award, findByUser query shape, updateDisplayed with and without IDs. - test/badges.e2e-spec.ts: e2e suite covering GET /badges (public, fields, all 7 keys present, criteria shape), GET /badges/users/:userId (empty, invalid UUID), PUT /badges/display (401 without token). AppModule: - BadgesModule registered in AppModule imports list.
Closes Rub-a-Dab-Dub#500 ## Summary Complete Voice Message module supporting secure pre-signed upload, confirmation, storage, playback metadata, waveform generation queue, and strict validation with tier-based duration limits. ## Entity VoiceMessage fields: - id (uuid PK) - messageId (uuid, indexed) - uploaderId (uuid, indexed) - fileKey (varchar 512, unique, indexed) - fileUrl (text) - duration (integer, nullable - set on confirm) - waveformData (jsonb, nullable - set async by queue) - mimeType (varchar 100) - fileSize (integer) - confirmed (boolean, default false) - createdAt (timestamp) ## Database Migration 1737000000000-VoiceMessagesSchema creates the voice_messages table with indexes on messageId, uploaderId, and fileKey. ## Repository (VoiceMessageRepository) - create, save, findById, findByFileKey - findByMessageId: returns confirmed-only records in ASC order - remove ## Service (VoiceMessagesService) - presign(user, dto): validates MIME type and tier-based duration limit, generates a pre-signed PUT URL expiring in 5 minutes (300s), returns uploadUrl, fileKey, fileUrl, expiresIn, expiresAt. - confirm(user, messageId, dto): idempotent - returns existing confirmed record unchanged; confirms pending record or creates new one; validates ownership; enqueues waveform generation fire-and-forget. - findById(id): returns DTO or 404. - findByMessageId(messageId): returns all confirmed voice messages. - delete(id, requesterId): ownership check, removes DB record and S3 file. ## Validation rules - Allowed MIME types: audio/ogg, audio/mp4, audio/webm only. - SILVER tier: max 300s (5 min). - GOLD / BLACK tier: max 600s (10 min). - Pre-signed URL TTL: 300s (5 min). - Invalid MIME type or exceeded duration throws BadRequestException. - Non-owner delete/confirm throws ForbiddenException. ## WaveformQueueService Async background queue (setTimeout-based, mirrors VirusScanQueueService pattern). Logs the job; replace processJob() with real ffprobe/ fluent-ffmpeg invocation. Swap for BullMQ when Redis queue is needed. ## Controller (POST|GET|DELETE /api/voice-messages/*) - POST /voice-messages/presign - generate upload URL - POST /voice-messages/messages/:messageId/confirm - confirm upload - GET /voice-messages/:id - fetch by ID - GET /voice-messages/messages/:messageId - fetch by message - DELETE /voice-messages/:id - delete (owner only) ## Module VoiceMessagesModule imports TypeOrmModule and AttachmentsModule (reuses S3StorageService). Exports VoiceMessagesService. ## Tests - voice-messages.service.spec.ts: 18 unit tests covering presign (valid, invalid MIME, SILVER over limit, GOLD at limit, GOLD over limit, all 3 MIME types), confirm (new, idempotent, wrong owner, invalid MIME in key), findById (found, 404), findByMessageId, delete (success, 404, forbidden). - voice-message.repository.spec.ts: 4 unit tests for findByMessageId query shape, findByFileKey, remove, save delegation. - test/voice-messages.e2e-spec.ts: e2e suite verifying 401 enforcement on all endpoints and 400 for invalid UUID params. ## AppModule VoiceMessagesModule registered in AppModule imports list.
Add comprehensive implementations of four backend modules with clean architecture,
proper validation, indexing, and full unit + e2e test coverage:
1. Blockchain Transaction Tracking Module (8 files)
- Records on-chain Stellar transactions independently from business transactions
- Entity with fields: id, userId, type (6 enums), txHash (unique, nullable),
status (4 states), fromAddress, toAddress, amountUsdc, feeStroops, ledger,
errorMessage, referenceId, timestamps
- DB indexes: (userId, createdAt DESC), unique txHash, referenceId, status
- Service methods: create(), updateStatus(), findByReference(), findByTxHash()
- Idempotent operations with proper state transitions
- Controllers: GET /blockchain/transactions (paginated, filterable), GET /blockchain/transactions/:id
- Full unit tests for lifecycle, idempotency, and filtering
- Full e2e tests with authorization checks
2. Message Forwarding Module (7 files)
- ForwardedMessage entity with proper chain tracking
- Service methods: forwardMessage(), forwardToMultiple() (max 5 targets),
getForwardedFrom(), getForwardChain() (depth limit: 3)
- Validation: forwarder is participant in both conversations,
prevents deleted message forwarding
- Content preservation without re-uploading
- POST /messages/:id/forward endpoint with validation
- WebSocket event hooks for message:new
- Full forward chain tracking with depth limits
- Complete unit and e2e tests
3. Poll Module (7 files)
- Poll entity with JSONB options array
- PollVote entity with option indexes array
- Service methods: createPoll() (2-10 options enforced),
castVote() (respects allowMultiple),
retractVote() (before close only),
closePoll() (creator-only),
getPoll(), getPollResults() (respects anonymity),
getPollsInConversation()
- @Cron scheduled job for auto-closing expired polls
- 6 REST endpoints for full poll lifecycle
- WebSocket event hooks for poll:updated
- Anonymous polls hide voter identity but expose totals
- Vote aggregation and accurate counting
- Comprehensive unit and e2e tests
4. Mention Module (7 files)
- Mention entity with read tracking
- Service methods: parseMentions() (regex @username pattern),
createMentions() (during message creation, no extra call),
markMentionRead(), getUnreadMentions(),
getMentionsInConversation(), getUnreadCount(),
markAllRead(), deleteByMessageId()
- Mention parsing: @([a-zA-Z0-9._-]+) with position tracking
- Validation: mentioned users are conversation participants
- 4 REST endpoints for mention management
- WebSocket event hooks for mention:new
- In-app and push notification hooks
- Batch mark-as-read operations
- Unread count accuracy tracking
- Full user ownership validation
- Complete unit and e2e tests
All modules include:
- Clean architecture with separation of concerns
- Strategic database indexing
- Production-safe idempotent operations
- Comprehensive input validation
- Complete error handling
- Unit test coverage (85%+)
- E2E test coverage (85%+)
- Swagger/OpenAPI documentation ready
- Proper authorization checks
Total: 34 files (29 source files + 4 e2e tests + 1 updated app.module)
- 25+ service methods
- 14 REST endpoints
- 4 scheduled jobs
- Full WebSocket event integration points
…ntegration-test-suite feat: add comprehensive e2e integration test suite (Rub-a-Dab-Dub#434)
…management feat: add legal consent management module
…ent-system feat(badges): implement Badge and Achievement system
…module feat(voice-messages): implement Voice Message module
…irdrop-distribution [Soroban] Airdrop & Reward Distribution Contract
…scrow-payment [Soroban] Escrow & Conditional Payment Contract
…taking-rewards [Soroban] Token Staking & Rewards Contract
…sername-registry [Soroban] Decentralized Username Registry Contract
- YieldStrategy storage: strategyId, protocolAddress, token, apy_bps, tvl, total_shares, isActive, lastUpdated - UserYieldPosition storage: user, strategyId, deposited, shares, lastHarvested - add_strategy(protocol, token) -> StrategyId — admin only; derives deterministic id via sha256(protocol_xdr ++ token_xdr) - deposit(user, strategy_id, amount) -> shares — transfers tokens into contract, mints shares proportional to current pool value - withdraw(user, strategy_id, shares) -> amount — burns shares, returns principal + accrued yield via token transfer back to user - harvest(strategy_id) — compounds 1% simulated yield into TVL; recalculates APY in basis points from realised yield / elapsed seconds - rebalance(from, to, amount) — moves TVL between strategies, admin only - get_apy, get_position, get_strategy view functions - Event emission for deposit, withdraw, harvest, rebalance - Full unit and integration test suite covering all functions, error paths, multi-user proportional yield, and APY updates
…b-Dub#642) - HistoryImportJob entity with PENDING/RUNNING/COMPLETED/FAILED status and resumable cursor field (stellar_history_import_jobs table) - StellarHistoryImporterService: importHistory, getImportStatus, syncNewTransactions, mapHorizonTxToInternal, deduplicateByTxHash, resumeFromCursor - Cursor-based Horizon pagination (200 tx/page); progress saved after each page so jobs are resumable on failure - Deduplication by txHash via ON CONFLICT DO NOTHING; graceful fallback when table does not exist on first run - HistoryImportProcessor (BullMQ WorkerHost) on stellar-history-import queue with 3 retries and exponential backoff - StellarHistoryImporterController: POST /wallets/:id/import-history (202 Accepted), GET /wallets/:id/import-status - WalletVerifiedListener auto-triggers import on wallet.verified event - Uses @stellar/stellar-sdk consistent with repo conventions - 22 unit tests covering all public methods, error paths, dedup, cursor resume, multi-page import, and sync
…Dub#645) - Add GeoRestriction and UserGeoRecord TypeORM entities - Implement GeoRestrictionService with OFAC fast-path (15 sanctioned countries), in-memory cache with 5-min TTL, and full CRUD for restriction rules - Add GeoRestrictionMiddleware resolving country from CDN headers (CF-IPCountry, X-Country-Code, CloudFront-Viewer-Country) with OFAC 403 fast-path - Add GeoFeatureGuard with @geofeature decorator for endpoint-level feature restrictions - Add GeoRestrictionController with admin and user-facing endpoints - Add GeoRestrictionModule wiring middleware to all routes - Add unit test suite covering all service methods Closes Rub-a-Dab-Dub#645
- Add OfflineMessageQueue TypeORM entity (QUEUED/DELIVERED/FAILED status, recipientId, messageId, conversationId, payload, attempts, deliveredAt) - Implement OfflineQueueService with Redis sorted-set queue (score = timestamp) and full CRUD: enqueue, dequeueForUser, markDelivered, retryFailed, getQueueDepth, flushOnConnect, pruneOld, getStats, persistStaleRedisEntries - Messages queued > 1 hour in Redis are persisted to PostgreSQL for durability (scheduled every 10 min via @Cron) - Delivered records pruned after 30 days (daily cron at 02:00) - flushOnConnect delivers all queued messages in strict chronological order bracketed by sync:start and sync:complete WebSocket events - Admin alert logged when any user's queue depth exceeds 1000 messages - OfflineQueueGateway hooks into /chat namespace OnGatewayConnection to auto-flush on user reconnect - OfflineQueueController: GET /admin/offline-queue/stats, POST /admin/offline-queue/flush/:userId - Unit test suite covering all service methods with mocked Redis + TypeORM Closes Rub-a-Dab-Dub#641
…and-OAuth2-Module feat: social login and OAuth2 Module.
feat: Soroban Yield Aggregator contract (Rub-a-Dab-Dub#648)
…y-importer feat: NestJS Stellar Transaction History Importer module (Rub-a-Dab-Dub#642)
feat: Geo-Restricted Access & Compliance Module (Rub-a-Dab-Dub#645)
feat: Offline Message Queue & Sync Module (Rub-a-Dab-Dub#641)
…-Module feat: User Blocking & Privacy Enforcement Module
…odule feat: Group Expense Splitting Module
…-Module feat: Bot & Webhook Integration Module
…Module feat: Terms & Consent Management Module
…le-415 feat: implement email module (closes Rub-a-Dab-Dub#415)
feat: implement api key module (closes Rub-a-Dab-Dub#425)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements Feature Flags module with runtime toggling and rollout control.
closes Rub-a-Dab-Dub#433
Explanation (max 3 lines):
Enables dynamic feature control without redeployment.
Uses Redis caching for fast evaluation.
Supports per-user, tier, and percentage rollout.