# 18. Backend Router — HomeTitle (Property Monitoring) meta: id: shieldai-unified-restructure-18 feature: shieldai-unified-restructure priority: P1 depends_on: [shieldai-unified-restructure-12, shieldai-unified-restructure-13, shieldai-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/` and `packages/api/src/routes/hometitle.routes.ts` into a unified `hometitle` router and service layer. deliverables: - `web/src/server/api/routers/hometitle.ts` — HomeTitle router: - `hometitle.getProperties` — `protectedProcedure` returning watched properties - `hometitle.addProperty` — `protectedProcedure` adding property to watchlist - `hometitle.removeProperty` — `protectedProcedure` removing property - `hometitle.getSnapshots` — `protectedProcedure` returning property record snapshots - `hometitle.getChanges` — `protectedProcedure` returning detected property changes - `hometitle.runScan` — `protectedProcedure` triggering manual property scan - `hometitle.getAlerts` — `protectedProcedure` returning property fraud alerts - `web/src/server/services/hometitle.service.ts` — Core business logic: - `addProperty(subscriptionId, address, parcelId?, ownerName?)` — geocode address, save record - `removeProperty(userId, propertyId)` — delete and cascade - `getSnapshots(propertyId)` — query snapshot history - `getChanges(propertyId, filters?)` — query changes with severity filtering - `runScan(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 APIs - `parseDeedRecords(html)` — extract ownership, date, lien info from HTML/PDF - `geocodeAddress(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 changes - `severityForChange(changeType, magnitude)` — determine severity level - `fuzzyMatchNames(name1, name2)` — Levenshtein distance for owner name comparison steps: 1. Create `web/src/server/api/routers/hometitle.ts`. 2. 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()` 3. Implement router procedures: - Property CRUD with subscription scoping - Snapshot and change queries - Manual scan with tier limit enforcement 4. Create `web/src/server/services/hometitle.service.ts`: - Port from `services/hometitle/src/` - Implement property geocoding on add - Implement scan orchestration 5. Create scanner module: - `fetchCountyRecords`: placeholder for county API integration. Many counties lack APIs — document which counties are supported. - `parseDeedRecords`: HTML parsing with Cheerio or similar - `geocodeAddress`: use Google Maps, OpenStreetMap, or similar geocoding service 6. 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 7. Implement alert pipeline: - On significant change (warning/critical), create `Alert` and `NormalizedAlert` - Trigger notification via task 14 service 8. Wire router into `web/src/server/api/root.ts`. 9. Write unit tests with mocked county data. steps: - Unit: `addProperty` geocodes address and creates record - Unit: `detectChanges` identifies ownership transfer and lien filing - Unit: `fuzzyMatchNames` handles minor spelling variations - Unit: `severityForChange` returns 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 test` for 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.