5.5 KiB
5.5 KiB
18. Backend Router — HomeTitle (Property Monitoring)
meta: id: kordant-unified-restructure-18 feature: kordant-unified-restructure priority: P1 depends_on: [kordant-unified-restructure-12, kordant-unified-restructure-13, kordant-unified-restructure-14] tags: [backend, trpc, hometitle, property, api]
objective:
- Build the tRPC router for HomeTitle, the property fraud monitoring service. Port all logic from
services/hometitle/andpackages/api/src/routes/hometitle.routes.tsinto a unifiedhometitlerouter and service layer.
deliverables:
web/src/server/api/routers/hometitle.ts— HomeTitle router:hometitle.getProperties—protectedProcedurereturning watched propertieshometitle.addProperty—protectedProcedureadding property to watchlisthometitle.removeProperty—protectedProcedureremoving propertyhometitle.getSnapshots—protectedProcedurereturning property record snapshotshometitle.getChanges—protectedProcedurereturning detected property changeshometitle.runScan—protectedProceduretriggering manual property scanhometitle.getAlerts—protectedProcedurereturning property fraud alerts
web/src/server/services/hometitle.service.ts— Core business logic:addProperty(subscriptionId, address, parcelId?, ownerName?)— geocode address, save recordremoveProperty(userId, propertyId)— delete and cascadegetSnapshots(propertyId)— query snapshot historygetChanges(propertyId, filters?)— query changes with severity filteringrunScan(userId)— scan all watched properties:- Fetch current county records
- Compare with last snapshot
- Detect changes: ownership transfer, lien filing, tax change, metadata change
generateAlert(change)— create alert if change severity is warning/critical
web/src/server/services/hometitle/scanner.ts— County record scanning:fetchCountyRecords(parcelId, county, state)— query county assessor/recorder APIsparseDeedRecords(html)— extract ownership, date, lien info from HTML/PDFgeocodeAddress(address)— convert address to lat/lng using geocoding API
web/src/server/services/hometitle/change.detector.ts— Change detection:detectChanges(oldSnapshot, newData)— compare fields and classify changesseverityForChange(changeType, magnitude)— determine severity levelfuzzyMatchNames(name1, name2)— Levenshtein distance for owner name comparison
steps:
- Create
web/src/server/api/routers/hometitle.ts. - Define Zod schemas:
addPropertySchema:address: z.string(),parcelId: z.string().optional(),ownerName: z.string().optional()changeFilterSchema:severity: z.enum(['info', 'warning', 'critical']).optional(),changeType: z.enum([...]).optional()
- Implement router procedures:
- Property CRUD with subscription scoping
- Snapshot and change queries
- Manual scan with tier limit enforcement
- Create
web/src/server/services/hometitle.service.ts:- Port from
services/hometitle/src/ - Implement property geocoding on add
- Implement scan orchestration
- Port from
- Create scanner module:
fetchCountyRecords: placeholder for county API integration. Many counties lack APIs — document which counties are supported.parseDeedRecords: HTML parsing with Cheerio or similargeocodeAddress: use Google Maps, OpenStreetMap, or similar geocoding service
- Create change detector:
- Compare snapshot fields: ownerName, address, deedDate, taxAmount, lienCount
- Use fuzzy string matching for owner names
- Classify changes into: ownership_transfer, lien_filing, tax_change, metadata_change
- Implement alert pipeline:
- On significant change (warning/critical), create
AlertandNormalizedAlert - Trigger notification via task 14 service
- On significant change (warning/critical), create
- Wire router into
web/src/server/api/root.ts. - Write unit tests with mocked county data.
steps:
- Unit:
addPropertygeocodes address and creates record - Unit:
detectChangesidentifies ownership transfer and lien filing - Unit:
fuzzyMatchNameshandles minor spelling variations - Unit:
severityForChangereturns correct severity per change type - Integration: tRPC procedures enforce subscription scoping
acceptance_criteria:
- Properties can be added with address geocoding and optional parcel ID
- Properties are scoped to the user's subscription
- Snapshots capture property record state at a point in time
- Changes are detected by comparing new data to last snapshot
- Manual scan can be triggered and respects tier limits
- Alerts are generated for warning/critical changes
- Fuzzy matching handles minor variations in owner names
validation:
- Add a test property, verify geocoding and record creation
- Simulate a snapshot change, verify change detection identifies the difference
- Run manual scan and verify scan completion
- Run
cd web && pnpm testfor HomeTitle unit tests
notes:
- Reference legacy:
services/hometitle/src/,packages/api/src/routes/hometitle.routes.ts - County record APIs are highly fragmented. The scanner should be designed as a plugin system where each county has its own adapter.
- For unsupported counties, the scan should gracefully degrade and inform the user.
- Property data may be sensitive. Ensure all records are encrypted at rest if required by compliance.
- Consider integrating with a third-party property data provider (e.g., CoreLogic, ATTOM) for broader coverage.
- The change detector should be configurable: users can choose which change types they want alerts for.