Repository navigation
test(properties): cover the listing surface, fix bulk error handling and add listing log events - #1474
Merged
nanaf6203-bit merged 2 commits intoOct 20, 2026
Conversation
… add listing log events Extends the Property API test pass (MettaChain#1363-MettaChain#1366, which covered create, lookups, remove and restore) over the listing routes, and fixes two real defects found while covering the bulk endpoints. - MettaChain#1381: `POST /properties/bulk/status` mapped the requested status with `status === DRAFT ? DRAFT : status === ARCHIVED ? ARCHIVED : ACTIVE`, so any other status fell through to ACTIVE. Bulk-marking listings SOLD or PENDING silently published every one of them and returned a success-looking `updatedCount`. Only DRAFT/ACTIVE/ARCHIVED are accepted now and anything else is a 400 naming the supported set, with nothing written. `POST /properties/bulk/delete` echoed the *requested* ids back as `propertyIds`, so deleting ['real', 'typo'] answered deletedCount 1 with both ids listed, which reads as if both had been removed. It now resolves which ids exist first and returns those, so the count and the list always agree; when nothing matches it short-circuits without touching the database. A foreign-key violation (P2003/P2014, i.e. a listing held by a transaction, document or commission) was an unhandled 500 carrying the raw driver message; it is now a 409 with the underlying error logged instead of returned. Both bulk methods reject an empty id list, which was previously a silent no-op indistinguishable from "nothing matched". docs/api/listings-error-handling.md - MettaChain#1382: added the AppLogger events the listing paths never emitted - search (with the filter *count* but never the filter values, so a slow search can be attributed to a query shape without addresses reaching the log stream), status transition including the idempotent no-op, approve/reject, all three bulk operations (each logging requestedCount alongside the affected count), expiry, the three agent-assignment operations and the three amenity operations. docs/api/listings-structured-logging.md - MettaChain#1379: unit suites added for searchProperties (paging, defaults, the forced ACTIVE/non-deleted filter, trust-score annotation and the in-memory branch, geo validation), transitionStatus/approve/reject (404/403/400, the no-op, the three allowed roles), bulk operations, agent assignment and amenities. The Prisma mock gained the updateMany/deleteMany/count/$transaction/propertyAgent/ propertyAmenity/user delegates. docs/api/listings-tests.md - MettaChain#1380: the HTTP suite now drives the status lifecycle (including that a refused transition is a 400 and that the caller role is forwarded), the bulk endpoints (id validation, reported ids, a 409 conflict), agent assignment, amenities, and the report download - which additionally asserts that an unexpected failure returns 500 without leaking the underlying error text. No tests were run and nothing was installed, built or linted; the new suites were written from the current service/controller code. Please verify in CI. Closes MettaChain#1379 Closes MettaChain#1380 Closes MettaChain#1381 Closes MettaChain#1382
|
@ustaxs 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! 🚀 |
Contributor
|
Tested it locally, works as expected. Merging. |
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.
Extends the Property API test pass (#1363–#1464, which covered create, lookups, remove and restore) over the listing routes — and fixes two real defects found while covering the bulk endpoints.
#1381 — Error handling (two genuine bugs)
Bulk status update silently published listings.
POST /properties/bulk/statusmapped the requested status with:Any status that was not
DRAFTorARCHIVEDfell through toACTIVE. Bulk-marking listingsSOLDorPENDINGtherefore published every one of them and returned a success-lookingupdatedCount. OnlyDRAFT/ACTIVE/ARCHIVEDare accepted now; anything else is a400naming the supported set, with nothing written.Bulk delete reported ids that were never deleted.
POST /properties/bulk/deletereturned{ deletedCount, propertyIds }wherepropertyIdswas the requested list echoed back unchanged. Deleting['real-id', 'typo-id']answered{ deletedCount: 1, propertyIds: ['real-id', 'typo-id'] }— which reads as if both had been removed. It now resolves which ids actually exist first and returns those, so the count and the list always agree. Cost: one extrafindMany({ select: { id: true } })on an admin-only endpoint.Foreign-key violations surfaced as opaque 500s. A listing held by a transaction, document or commission made Prisma throw
P2003/P2014, reaching the client as an unhandled500carrying the raw driver message — internal schema detail in an error body. Now a409with the underlying error logged (properties.bulk_delete_conflict) rather than returned. Any other error still propagates unchanged.Empty id lists are rejected with
400. The DTOs already enforced@ArrayMinSize(1)at the HTTP boundary, but the service methods are called directly too, andupdateMany/deleteManywith an emptyinlist is a silent no-op reportingupdatedCount: 0— indistinguishable from "nothing matched".→
docs/api/listings-error-handling.md#1382 — Structured logging
Added the
AppLoggerevents the listing paths never emitted:properties.searchproperties.status_transitioned,properties.status_transition_noop,properties.approved,properties.rejectedproperties.bulk_status_updated,properties.bulk_deleted,properties.bulk_delete_no_match,properties.bulk_delete_conflict,properties.bulk_exportedproperties.expiredproperties.agent_assigned,properties.agent_assignment_updated,properties.agent_assignment_removedproperties.amenity_added,properties.amenity_updated,properties.amenity_removedTwo details worth reviewing:
properties.searchlogs how many filters were supplied, never their values — so "every search with 8 filters is slow" is diagnosable without addresses, cities or owner names reaching the log stream. Paging and sorting are excluded, sincepage/limitare always present because the DTO defaults them.requestedCountalongside the affected count. That is the same gap the delete fix above closes, on the observability side.→
docs/api/listings-structured-logging.md#1379 — Unit tests
New suites over the listing surface that had none:
searchProperties— paging arithmetic and reported total, the defaults (page 1,20/page, newest first), that the query is forced toACTIVEand non-deleted whateverstatusthe caller passed, theneighborhoodTrustScoreannotation, the in-memory trust-score branch (and that it bypasses the transaction), and geo validation:latwithoutlngrejected, radius with no centre rejected, radius converted to a bounding box.transitionStatus/approve/reject—404unknown,403for a caller who is neither owner/agent/admin,400for a disallowed transition, the idempotent no-op that does not write, the three roles that are allowed, and approve→ACTIVEvs reject→ARCHIVED.propertyIdsreports only ids that existed, the no-match short circuit, andP2003→ conflict.404/403/role/duplicate guards, the 3% default commission,404on updating or removing an assignment that does not exist, and the contact-detail fallback ingetAgents.404unknown listing, refusal to touch an amenity belonging to a different listing, theisAvailabledefault, oldest-first ordering.The Prisma mock gained the
updateMany,deleteMany,count,$transaction,propertyAgent,propertyAmenityanduserdelegates.→
docs/api/listings-tests.md#1380 — Integration tests
The HTTP suite now drives the routes it did not touch:
400; surfaces a refused transition as400;approve/rejectadmin-only.409, and the optional export filter.404, unauthenticated read.404, and an unexpected failure returns500without leaking the underlying error text into the body.Not run
Per instructions nothing was installed, built, linted or tested. The new suites were written from the current service and controller code, and the expectations were read off that code rather than observed — please verify in CI, since assertions that never ran are the main risk here.
Closes #1379
Closes #1380
Closes #1381
Closes #1382