Repository navigation
feat(properties): OpenAPI specs, input sanitization, search-builder extraction and retry with backoff for the Property API - #1472
Open
ayshadogo wants to merge 2 commits into
Conversation
…xtraction, retry with backoff Documentation, input hygiene and resilience work on the Property API (`src/properties`), following the conventions of the Users API pass in MettaChain#1457-MettaChain#1463. - MettaChain#1371: every PropertiesController route now carries @apioperation (with a stable operationId), @ApiParam, @ApiBody, @ApiProduces and the @apiresponse codes the route really returns, including the 401/403 role gates that were undocumented. The project does not enable the @nestjs/swagger CLI plugin (nest-cli.json has no `plugins`), so @ApiBody({ type }) would emit an empty schema; @ApiProperty/@ApiPropertyOptional were added to CreatePropertyDto, UpdatePropertyDto, TransitionPropertyStatusDto, the bulk-operation DTOs and the amenity DTOs. docs/api/properties-openapi.md - MettaChain#1372: sanitize.util.ts normalises every string in a property write body via class-transformer @Transform callbacks on Create/UpdatePropertyDto, which the existing global ValidationPipe already runs. Free text (title, description, HOA fields) is stripped of control characters, HTML tags and whitespace runs; identifiers (address, city, state, zip, country, type, category) are trimmed; string arrays are cleaned element-wise. NFKC normalisation matters here because visually identical values otherwise defeat the duplicate-address check. Values are normalised, not rejected, so no client starts getting 400s it did not get before. docs/api/properties-input-sanitization.md - MettaChain#1373: buildSearchWhereClause moved verbatim out of the 1200-line service into search-where.builder.ts. It is a pure function of its input with no I/O and no `this`, and it was a 155-line private method. No filter was added, removed or reordered, so the existing quirks (exact bedroom/bathroom filters beating the ranges, ACTIVE-only public results, radius approximated as a bounding box) are all preserved. docs/api/properties-refactor.md - MettaChain#1374: retryWithBackoff now wraps the geocoding provider call in attemptGeocode (3 attempts, 200ms base, 2s cap, up to 50% jitter). isTransientGeocodeError retries 429, 5xx, timeouts and socket errors but not a 4xx, because repeating a request the provider already rejected only burns the per-minute geocoding budget. Exhausting the retries still creates the property without coordinates, exactly as before. docs/api/properties-retry.md Nothing was installed, built, linted or tested; please verify in CI. Closes MettaChain#1371 Closes MettaChain#1372 Closes MettaChain#1373 Closes MettaChain#1374
|
@ayshadogo 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 branch has not been deployed
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.
Documentation, input hygiene and resilience work on the Property API (
src/properties), following the conventions of the Users API pass in #1457–#1463.#1371 — OpenAPI specs
Every
PropertiesControllerroute now carries@ApiOperation(with a stableoperationId),@ApiParam,@ApiBody,@ApiProducesand the@ApiResponsecodes the route actually returns — including the 401/403 role gates that were previously undocumented.One thing worth flagging: the project does not enable the
@nestjs/swaggerCLI plugin (nest-cli.jsonhas nopluginsentry), so@ApiBody({ type: SomeDto })on its own emits an empty schema.@ApiProperty/@ApiPropertyOptionalwere therefore added to the DTOs a body references:CreatePropertyDtoPOST /propertiesUpdatePropertyDtoPUT /properties/:idTransitionPropertyStatusDtoPATCH /properties/:id/statusBulkPropertyStatusUpdateDto/BulkPropertyDeleteDto/BulkPropertyExportDtoPOST /properties/bulk/*CreateAmenityDto/UpdateAmenityDtoPOST/PATCH /properties/:id/amenitiesAssignAgentDto/UpdateAgentAssignmentDtoalready had@ApiProperty.Examples are given where the accepted format is not obvious (currency, enums, date-time, URI, UUID), and
statusonUpdatePropertyDtopoints atPATCH /properties/:id/status, which is the route that actually enforces the lifecycle workflow.GET /propertiesandGET /properties/searchare deliberately not covered here — they are documented in the ListingAPI OpenAPI PR.→
docs/api/properties-openapi.md#1372 — Input sanitization
src/properties/sanitize.util.tsnormalises every string in a property write body, wired in asclass-transformer@Transformcallbacks onCreatePropertyDto/UpdatePropertyDto. The globalValidationPipeinsrc/main.tsalready runs withtransform: true, so the pipe configuration did not need to change.CleanTexttitle,description,hoaName,hoaContactInfoTrimIdentifieraddress,city,state,zipCode,country,propertyType,categoryCleanIdentifierListfeatures,tags,hoaAmenitiesTrimIdentifierper elementTwo of these are specifically about this data model:
createbe bypassed and produces two "different" versions of the same property.Values are normalised, not rejected. Invalid input still fails validation with
400exactly as before, so no existing client starts receiving errors it did not get already.→
docs/api/properties-input-sanitization.md#1373 — Refactor: search filter building
PropertiesServicehad grown past 1200 lines andbuildSearchWhereClausealone was a 155-line private method. It reads aSearchPropertiesDto, does no I/O and uses nothis— a pure function that was stuck inside a large class.It moved verbatim to
src/properties/search-where.builder.tsas an exportedbuildSearchWhereClause(dto). No filter was added, removed or reordered, so the existing quirks are all preserved: exactbedrooms/bathroomsfilters beating the corresponding ranges,ACTIVE-only results on the public search regardless of thestatuspassed,locationmatching address/city/state/zip withOR, and a radius approximated with a bounding box that is rejected unlesslat/lngcome as a pair. Geo validation still throwsBadRequestException.→
docs/api/properties-refactor.md#1374 — Retry with backoff
Geocoding is the only outbound call the Property API makes, and it runs inside
attemptGeocodeon create and on address change. It now runs underretryWithBackoff: 3 attempts, 200 ms base delay, 2 s cap, up to 50% jitter so concurrent callers do not retry in lockstep.isTransientGeocodeErrordecides what is worth another attempt —429, any5xx,TimeoutError/AbortError, and socket errors (ECONNRESET,ECONNREFUSED,EAI_AGAIN,ENOTFOUND,socket hang up,fetch failed). A4xxother than429is not retried: the provider already rejected the request, and repeating it only burns the per-minute geocoding budget thatattemptGeocodealready enforces.Behaviour deliberately unchanged:
markGeocodingFailedstill runs, so a transient provider outage costs latency rather than the whole create.null, not an error, so it is never retried.sleepandrandomare injectable so the delay schedule is testable without waiting in real time.→
docs/api/properties-retry.mdScope
Four self-contained changes plus one doc under
docs/api/per issue. Nothing was installed, built, linted or tested — please verify in CI. The existing service spec was checked by reading, not running: it assertsgeocodeAddressis not called when coordinates are supplied, which the retry wrapper does not change.Closes #1371
Closes #1372
Closes #1373
Closes #1374