eng-308-lender portfolio#470
eng-308-lender portfolio#470Connorbelez wants to merge 3 commits intocodex/eng-302-explicit-borrower-portal-attributionfrom
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…s.ts, helpers.ts, and queries.ts now define the command-center contract plus the { portalId, mortgageId } and { portalId, obligationId } detail reads, all behind portalLenderQuery and portfolio:view. I also extracted shared lender-constraint logic into lenderConstraints.ts and rewired portalQueries.ts to reuse it, so lender listing limits and portfolio suggestions now share one source of truth. The new portfolio suite in queries.test.ts covers empty state, unauthorized access, ownership math, individual payment rows, broker context, and ordered suggestion exclusion. The ENG-308 workflow artifacts under status.md and audit.md are updated through a passing final validator.
… undefined from allowed === [], so explicit empty allowlists stay deny-all instead of disabling lender constraints. In helpers.ts, the command-center suggestion rail now keeps paging marketplace results until it collects 5 non-owned suggestions or exhausts the filtered set, instead of truncating before owned-listing exclusion. I also added regression coverage in queries.test.ts and queries.test.ts for empty stored allowlists and for backfilling suggestions when owned listings dominate the first page. Validation passed: bun check completed with the repo’s existing out-of-scope complexity warnings, bunx convex codegen passed, bun typecheck passed, and bun run test -- convex/portfolio/__tests__/queries.test.ts convex/listings/__tests__/queries.test.ts passed with 25 tests.
a8482cb to
4c613e9
Compare
There was a problem hiding this comment.
Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Pull request overview
Implements ENG-308 by introducing a dedicated convex/portfolio backend module that exposes lender portfolio command-center and detail-sheet queries (position/payment) using portalLenderQuery + portfolio:view, and centralizes lender listing constraint logic for reuse across listings and portfolio.
Changes:
- Added portfolio contracts, helper composition logic, and public queries for command-center + detail sheets.
- Extracted lender constraint loading/clamping into
convex/listings/lenderConstraints.tsand rewired portal listing queries to use it. - Added focused portfolio query tests and updated listing tests for the empty-allowlist (deny-all) regression; updated ENG-308 spec artifacts.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| specs/ENG-308/tasks.md | Task breakdown for ENG-308 execution. |
| specs/ENG-308/summary.md | Scope/constraints summary for the ENG-308 backend slice. |
| specs/ENG-308/status.md | Execution status + validation notes. |
| specs/ENG-308/execution-checklist.md | Requirements/DoD checklist and coverage expectations. |
| specs/ENG-308/chunks/manifest.md | Chunk manifest for the ENG-308 implementation plan. |
| specs/ENG-308/chunks/chunk-01-constraints-and-contracts/* | Chunk artifacts documenting constraint extraction + contract scaffolding. |
| specs/ENG-308/chunks/chunk-02-command-center-query/* | Chunk artifacts documenting the command-center query work. |
| specs/ENG-308/chunks/chunk-03-detail-queries-and-tests/* | Chunk artifacts documenting detail queries + tests + validation. |
| specs/ENG-308/audit.md | Spec compliance audit ledger and evidence pointers. |
| convex/test/moduleMaps.ts | Registers new modules in the Convex test module map. |
| convex/portfolio/queries.ts | Public, portal-scoped lender portfolio query endpoints. |
| convex/portfolio/helpers.ts | Portfolio composition logic for cockpit/positions/payments/actions/limits/suggestions and detail sheets. |
| convex/portfolio/contracts.ts | DTO validators + inferred TS types for portfolio payloads. |
| convex/portfolio/tests/queries.test.ts | Portfolio query test suite covering empty state, auth, ownership math, details, suggestions, broker context. |
| convex/listings/portalQueries.ts | Reuses extracted lender constraint helpers for lender portal listing visibility and effective filters. |
| convex/listings/lenderConstraints.ts | New centralized lender constraint loader + filter clamping utilities. |
| convex/listings/tests/queries.test.ts | Regression test for empty allowlists behaving as deny-all. |
| convex/_generated/api.d.ts | Codegen update to include new modules. |
| CLAUDE.md | Updates GitNexus index metadata. |
| AGENTS.md | Updates GitNexus index metadata. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const positionUnits = | ||
| positions.find( | ||
| (position) => String(position.mortgageId) === String(mortgage._id) | ||
| )?.balanceUnits ?? 0; | ||
| return accumulateBreakdown(rows, mortgage.status, positionUnits); |
| const legacyAccounts = ( | ||
| await ctx.db.query("ledger_accounts").collect() | ||
| ).filter( | ||
| (account) => | ||
| account.type === "POSITION" && | ||
| getAccountLenderId(account) === lenderAuthId | ||
| ); | ||
|
|
| const transferEntries = await Promise.all( | ||
| obligations.map(async (obligation) => { | ||
| const transfers = await ctx.db | ||
| .query("transferRequests") | ||
| .withIndex("by_obligation", (query) => | ||
| query.eq("obligationId", obligation._id) | ||
| ) | ||
| .collect(); |
| const pageCandidates = await Promise.all( | ||
| snapshot.page.map(async (suggestion) => { | ||
| const listingId = suggestion.id as Id<"listings">; | ||
| const listing = await ctx.db.get(listingId); | ||
| if (!listing) { | ||
| return null; | ||
| } | ||
| return { listing, suggestion }; | ||
| }) | ||
| ); | ||
|
|
||
| for (const candidate of pageCandidates) { | ||
| if (!candidate) { | ||
| continue; | ||
| } | ||
| if ( | ||
| candidate.listing.mortgageId && | ||
| args.heldMortgageIds.has(String(candidate.listing.mortgageId)) | ||
| ) { | ||
| excludedOwnedMortgageCount += 1; | ||
| continue; | ||
| } | ||
| if (rows.length < SUGGESTED_OPPORTUNITY_LIMIT) { | ||
| rows.push(candidate); |
| do { | ||
| const snapshot = await listMarketplaceListingsSnapshot( | ||
| ctx, | ||
| { | ||
| cursor, | ||
| filters: args.filters, | ||
| numItems: SUGGESTED_OPPORTUNITY_PAGE_SIZE, | ||
| }, | ||
| { pricingPolicy: args.pricingPolicy } | ||
| ); |
| PortfolioTimelineEvent, | ||
| } from "./contracts"; | ||
|
|
||
| const DAYS_PER_MILLISECOND = 1000 * 60 * 60 * 24; |

fix(portals): address eng-302 review feedback
Implemented ENG-308 in a dedicated portfolio backend module. contracts.ts, helpers.ts, and queries.ts now define the command-center contract plus the { portalId, mortgageId } and { portalId, obligationId } detail reads, all behind portalLenderQuery and portfolio:view. I also extracted shared lender-constraint logic into lenderConstraints.ts and rewired portalQueries.ts to reuse it, so lender listing limits and portfolio suggestions now share one source of truth. The new portfolio suite in queries.test.ts covers empty state, unauthorized access, ownership math, individual payment rows, broker context, and ordered suggestion exclusion. The ENG-308 workflow artifacts under status.md and audit.md are updated through a passing final validator.
clampEnumValues in lenderConstraints.ts now distinguishes allowed === undefined from allowed === [], so explicit empty allowlists stay deny-all instead of disabling lender constraints. In helpers.ts, the command-center suggestion rail now keeps paging marketplace results until it collects 5 non-owned suggestions or exhausts the filtered set, instead of truncating before owned-listing exclusion.
I also added regression coverage in queries.test.ts and queries.test.ts for empty stored allowlists and for backfilling suggestions when owned listings dominate the first page. Validation passed: bun check completed with the repo’s existing out-of-scope complexity warnings, bunx convex codegen passed, bun typecheck passed, and bun run test -- convex/portfolio/tests/queries.test.ts convex/listings/tests/queries.test.ts passed with 25 tests.