feat(notifications): real-time WebSocket invoice event notifications (#9) - #1
Open
Mhidesav wants to merge 23 commits into
Open
feat(notifications): real-time WebSocket invoice event notifications (#9)#1Mhidesav wants to merge 23 commits into
Mhidesav wants to merge 23 commits into
Conversation
…gination, and empty state
…ons (Nova-reward#9) - Add NestJS WebSocket gateway (NotificationsGateway) that broadcasts invoice lifecycle events (created, submitted, funded, repaid, defaulted) to all connected Socket.IO clients - Add NotificationsModule wiring gateway into AppModule - Add InvoiceEvent DTO with typed event names - Add 4 backend unit tests (Jest) covering broadcast and publish flows - Add React useInvoiceNotifications hook (socket.io-client) that subscribes to invoice_event and tracks connection state - Add 5 frontend unit tests covering connect, event accumulation, ordering, and cleanup - Add GitHub Actions app-ci.yml workflow running backend and frontend tests on changes to backend/** or frontend/**
…unit test suite The core Soroban contracts had no automated tests because the contracts themselves did not yet exist in the repo. This adds a Cargo workspace under contracts/ with the two contracts under test and a comprehensive unit-test suite using soroban_sdk::testutils. invoice contract: - mint (auth + zero/negative-value rejection, monotonic ids) - transfer (ownership, non-owner / self-transfer / missing-invoice guards) - update_status lifecycle state machine (Pending/Funded/Settled/Defaulted) - metadata retrieval views (get_invoice, owner_of, status_of, exists) financing-pool contract: - deposit / withdraw with auth and balance/liquidity guards - fund_invoice with discounted advance - discount calculation (quote / discount_amount, basis points, floor rounding) Edge cases covered: zero-value funding, duplicate invoice ids, unauthorized callers, illegal state transitions, insufficient liquidity/balance. CI: .github/workflows/contracts.yml runs cargo fmt --check, clippy -D warnings, and cargo test on every push and PR. All 45 tests pass locally. Closes Nova-reward#11
Funded invoices become transferable on-chain ownership tokens representing the repayment claim. Invoices are non-fungible, so the interface is NFT-flavored (one unique token per invoice) using SEP-0041 naming and the approve / transfer_from delegation pattern. - fund(invoice_id, discount_rate): canonical Pending -> Funded transition that mints the invoice's unique token and snapshots its metadata (invoice id, face value, discount rate, due date). Replaces the update_status funding path. - get_invoice_token / get_invoice_token_owner / is_tokenized query functions. - approve / get_approved / transfer_from for delegated transfers; approval is consumed on transfer and cleared on any direct transfer. - transfer is blocked once an invoice is repayment-settled. Tests: +19 invoice tests (token mint/metadata, ownership queries, transfer rules incl. post-repayment block, approve/transfer_from, auth). Existing lifecycle tests migrated to the fund() path. 64 tests pass; fmt + clippy clean. Note: the "frontend displays token ownership" criterion is not addressed here because the repo has no frontend application yet (frontend/ contains only a Dockerfile). The get_invoice_token_owner / get_invoice_token views expose exactly what an invoice detail page needs to consume. Closes Nova-reward#8
Funded invoices stayed FUNDED after the settlement contract repaid them on-chain because there was no backend listener for the InvoiceSettled event. This adds the NestJS + Prisma backend (the repo previously had only a Dockerfile) with a Soroban settlement listener. - soroban-events.service: polls Soroban RPC getEvents and decodes XDR topics/value into native values. - settlement-event.parser: pure parser recognizing InvoiceSettled events and extracting the invoice id. - settlement.service: FUNDED -> REPAID via a conditional updateMany in a transaction — atomic and idempotent (replayed events are a no-op). - settlement-sync.service: polls every 5s (dashboards reflect within ~10s), settles each event through withRetry (max 3 attempts, exponential backoff), and only advances the ledger cursor past fully-processed ledgers so a failing event is retried next cycle instead of being skipped. - invoices/dashboard REST endpoints + /health so dashboards read fresh status. - Prisma schema (Invoice, SyncCursor) + initial migration. Tests: 21 unit tests (retry backoff, event parsing, atomic/idempotent settlement, cursor advancement + retry/resume), all mocked so they run with no DB or chain. npm test and npm run build pass. Closes Nova-reward#3
… nonce replay protection Adds a new contracts/ workspace containing three Soroban (Rust) smart contracts for the InvoiceFi Stellar protocol: invoice, financing-pool, and settlement. Security hardening: - Every mutating entry point calls env.require_auth(&caller) before any business logic. - settlement.settle_invoice accepts a nonce: u64 parameter; used nonces are persisted in contract storage and rejected on reuse, preventing replay attacks. - Nonce entries expire after invoice due_date + 30 days (2592000 s) to bound storage growth. - get_used_nonces read function exposed for on-chain auditability. - contracts/SECURITY.md documents the full authorization model, role hierarchy, nonce mechanism, event observability, and audit checklist.
test: implement invoice lifecycle e2e tests
…tract-test-suite test(contracts): Soroban invoice & financing-pool contracts with unit test suite
…-tokenization feat(invoice): SEP-0041-style NFT tokenization of funded invoices
…tatus-sync fix(backend): sync invoice status to REPAID on on-chain settlement
…o-table Add investor portfolio dashboard scaffold with sorting, filtering, pa…
feat(contracts): add Soroban smart contracts with systematic auth and…
Redesign invoice creation flow with multi-step wizard
feat: implement investor pool metrics dashboard
feat: implement role-based access control for frontend and backend
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
Closes Nova-reward#9
Implements real-time notifications for invoice lifecycle events via WebSocket (Socket.IO).
Changes
Backend (NestJS)
NotificationsGateway— WebSocket gateway broadcastinginvoice_eventto all clients; acceptspublish_invoice_eventfrom clientsNotificationsModule— wires the gatewayInvoiceEventDTO — typed interface (created | submitted | funded | repaid | defaulted)Frontend (React)
useInvoiceNotificationshook — connects via Socket.IO, tracks connection state, returns events most-recent-firstCI
.github/workflows/app-ci.yml— runs backend + frontend Jest tests on push/PR tobackend/**orfrontend/**Tests