Title: feat: durable notification queue, gated content, expanded games API - #1539
Merged
Conversation
|
@vitalis200 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Summary
Implements four backend tickets:
closes #1439 — Durable notification email queue: emails are now persisted to a new email_outbox table before delivery, with pluggable ConsoleEmailAdapter (default) and SmtpEmailAdapter (raw net/tls, no new deps) implementations selected via SMTP_HOST. Failed sends stay pending and are retried by a scheduled worker; sentEmails/getSentEmails() behavior is preserved for backward compatibility.
closes #1440 — Persist notification retry/digest state: the subscription-lifecycle retry queue and digest windows (previously only in-memory Maps on NotificationsService) are now mirrored to notification_retry_jobs and notification_digest_windows tables and rehydrated on onModuleInit, so pending retries/digests survive a restart. A NotificationRetryWorkerService ticks every 60s to drain the retry queue and re-attempt pending outbox emails. Email sends now check the recipient's email_subscription_renewal preference (via UsersService), failing open on lookup errors.
closes #1442 — Gated-content checks on content reads: new ContentAccessService gates GET /v1/content/:id on subscription_tier — public content and content owners get the full payload, active subscribers (via SubscriptionsService#isSubscriber) get the full payload, everyone else gets a teaser with description/ipfs_cid/ipfs_url stripped. A new OptionalJwtAuthGuard lets the route resolve an optional requester identity without requiring auth.
closes #1441 — Expand games API: adds POST /v1/games/:id/start (host-only, PENDING→IN_PROGRESS, needs ≥2 players), POST /v1/games/:id/leave (removes the player, reassigns host to the next-lowest turn order, or clears it), and POST /v1/games/:id/score (updates a player's balance while IN_PROGRESS). A new host_user_id column on Game is set to the first player to join. Invalid state transitions return 400; non-host start returns 403.
All new persistence/DI is wired as optional dependencies on NotificationsService so every existing unit test keeps passing unchanged — production NotificationsModule always supplies the durable stores, which is what gives the service its durability.
Notes / follow-ups
ContentAccessService's subscriber check reuses SubscriptionsService#isSubscriber, which is keyed on Stellar addresses on-chain; until platform user IDs are bridged to wallet addresses (see the existing caveat on HybridFanAuthGuard), this treats requesterId/creator_id as opaque identity strings.
GamesModule/ContentModule are still not registered in AppModule — pre-existing, left as-is (out of scope for these tickets).
SmtpEmailAdapter is an intentionally basic stub (no STARTTLS upgrade, assumes single-chunk server replies) — swap for a hardened library-backed client before production mail volume.
Test plan
npm test --prefix backend (new specs: games start/leave/score, ContentAccessService, OptionalJwtAuthGuard, email adapters, EmailOutboxService, retry/digest stores, retry worker, notifications persistence integration)
Run the new migration (1750000000000-CreateNotificationDurableState) against a scratch DB
Manually exercise GET /v1/content/:id as anonymous / non-subscriber / subscriber / owner
closes #