Architecture & Multi-State Reconnaissance
Phase 1P · 5 states now LIVE (CT, NY, NJ, OH, FL) via verified $0 public GIS endpoints. Commercial-use & redistribution UNVERIFIED for all sources. No paid services, no outreach. $0/month maintained. Current cost: $0.00.
NormalizedProperty model. Missing fields are marked source_unavailable / not_supported — never false. PA/TX/AZ/CA remain on county-fallback (NOT_CONNECTED). Financial engine untouched.10-State Public Data Coverage Matrix (10 states)
| State | Parcel | Owner | Mailing | CAMA | Tax Delinq | Foreclosure | Code/Blight | Probate | Liens | Listing |
|---|---|---|---|---|---|---|---|---|---|---|
| Connecticut | 🟢 LIVE PUBLIC ($0) | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| New York | 🟢 LIVE PUBLIC ($0) | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| New Jersey | 🟢 LIVE PUBLIC ($0) | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Pennsylvania | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Rhode Island | 🟢 LIVE PUBLIC ($0) | ❌ | ❌ | ❌ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Ohio | 🟢 LIVE PUBLIC ($0) | ❌ | ❌ | ❌ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Florida | 🟢 LIVE PUBLIC ($0) | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Texas | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| Arizona | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
| California | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ✅ | ✅ | ✅ | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | 🟡 MANUAL PUBLIC / DOWNLOAD ONLY | ⚫ NOT AVAILABLE |
6 states have verified free statewide parcel geometry: Connecticut, New York, New Jersey, Rhode Island, Ohio, Florida.
4 states require county-by-county adapters (no single statewide attribute service): Pennsylvania, Texas, Arizona, California.
Owner/mailing/CAMA availability varies by state even where parcel geometry is free — NY & RI public parcel layers are geometry-only. Distress fields (tax delinquency, foreclosure, probate, liens) are manual-portal-only in every state at $0.
County-Level Fallback Architecture
| State | Statewide Adapter | County Adapters | Behavior | Notes |
|---|---|---|---|---|
| Connecticut | ctPublicGisProvider | — | statewide only | Statewide CT CAMA covers all 169 towns. No county fallback needed. |
| New York | nyParcelsProvider | — | statewide only | Geometry statewide; owner/CAMA requires county or paid enrichment (future). |
| New Jersey | njModivProvider | — | statewide only | MOD-IV composite is statewide. Strongest free CAMA. |
| Pennsylvania | — | Monroe | county only | 67 autonomous counties. County-by-county adapter required. Monroe UNVERIFIED. |
| Rhode Island | riRigisProvider | — | statewide only | RIGIS geometry statewide; CAMA via municipal assessor (future). |
| Ohio | ohOgripProvider | Franklin | use statewide then county | OGRIP statewide + county auditor CAMA where available. |
| Florida | flFgioProvider | — | statewide only | FGIO statewide parcels from 67 county property appraisers. |
| Texas | — | Bexar, Harris | county only | No statewide attribute service. County CADs hold CAMA. |
| Arizona | — | Pima, Maricopa | county only | County open-data portals; no statewide attribute service. |
| California | — | Los Angeles, San Diego | county only | 58 counties; LA publishes statewide boundary geodatabase (geometry only). |
Each state may have a statewide adapter OR fall back to per-county adapters. Different jurisdictions can use different sources. All adapters normalize into the same internal model — no screen consumes state-specific schemas.
Normalized Multi-State Data Model
Every state's raw schema (CT CAMA, NY parcels, NJ MOD-IV, etc.) is normalized into one internal NormalizedProperty with coverage-aware fields:
Missing state/county coverage NEVER silently becomes FALSE. Every field retains provenance. Raw state-specific attributes are kept for traceability but never consumed directly by app screens.
National-Ready Provider Registry
| State | Provider | Coverage | Fields | Cost | Status |
|---|---|---|---|---|---|
| Connecticut | ctPublicGisProvider | Statewide (169 towns) | geometry, apn, owner, mailing, assessment, beds, baths, living_area, sale_history | $0 | LIVE |
| New York | nyParcelsProvider | Statewide (county-permission-dependent) | geometry, apn, owner, mailing, assessment, market_value, beds, living_area, year_built, acreage | $0 | LIVE |
| New Jersey | njModivProvider | Statewide (21 counties) | geometry, apn, owner, mailing, assessment, land_use, beds, sale_history, year_built | $0 | LIVE |
| Ohio | ohOgripProvider | Statewide (88 counties) | geometry, apn, situs_address, land_use_code | $0 | LIVE |
| Pennsylvania | paMonroeGisProvider | Monroe County | geometry, apn | UNKNOWN | NOT_CONNECTED |
| Rhode Island | riRigisProvider | Statewide (geometry) | geometry, apn | $0 | NOT_CONNECTED |
| Florida | flFgioProvider | Statewide (67 counties, 10.8M parcels) | geometry, apn, owner, mailing, assessment, just_value, living_area, year_built, sale_history, acreage | $0 | LIVE |
| Texas | txCountyCadProvider | County-by-county | geometry, apn, owner, assessment | UNKNOWN | NOT_CONNECTED |
| Arizona | azCountyProvider | County-by-county | geometry, apn, owner | UNKNOWN | NOT_CONNECTED |
| California | caCountyProvider | County-by-county | geometry, apn, owner, assessment | $0 | NOT_CONNECTED |
Only CT is LIVE. All others NOT_CONNECTED until explicitly approved + endpoint-verified. No faked nationwide coverage.
Phase 1P — Live Provider Verification (NY / NJ / OH / FL)
CORRECTS Phase 1O matrix (which said geometry-only). Layer 1 carries owner/mailing/CAMA. Coverage is county-permission-dependent — some counties absent. Commercial redistribution terms UNVERIFIED; internal lookup use only until confirmed.
Strongest free CAMA-equivalent of the 10 states. MOD-IV = tax assessment table joined to parcels. License text states data is 'not survey data.' Commercial redistribution terms UNVERIFIED — internal lookup use only.
HONEST LIMITATION: public 'full view' layer carries geometry + parcel ID + SitusAddressAll ONLY. Owner/mailing/CAMA fields exist in schema but are BLANK — CAMA lives at county auditor open-data portals (e.g. Franklin). OGRIP states 'no use restrictions' but redistribution UNVERIFIED. ownerName/mailing marked source_unavailable in adapter.
Very rich: owner, mailing, just-value, assessed value, living area, year built, sale price/date. FDOR data is public record per FL law, but commercial redistribution inside a paid SaaS UNVERIFIED. Internal lookup use only until confirmed.
Coverage symbols: ✓ Available · — Not provided by this source (does NOT mean the real-world fact is absent) · ✗ Confirmed absent. OH owner/mailing/CAMA are blank in the public layer — marked source_unavailable, never false.
Multi-Tenant SaaS Architecture (Design Only)
| Area | Requirement | MVP Status |
|---|---|---|
| User authentication | Email/password + OAuth; secure session; password reset | not configured |
| Investor accounts | Per-user profile, preferences, plan tier | not configured |
| Tenant isolation | Every user-owned record scoped by tenantId; row-level security | designed |
| Durable database | Relational/JSON store surviving restart + rebuild | not configured |
| Encryption/security | TLS in transit; encryption at rest; secrets management | not configured |
| Roles | Owner / Team member / Viewer (future) | designed |
| Backups | Automated + point-in-time recovery | not configured |
| Data export/deletion | GDPR/CCPA-style export + delete | partial |
| Usage metering | Track API calls, map tiles, saved-search runs per tenant | not configured |
| Subscription/billing | Stripe or equivalent; plan limits enforced | not configured |
| Plan limits | Free / Pro / Team tiers with property + search caps | designed |
| Customer onboarding | Signup → state selection → first property import | designed |
| Account recovery | Email reset, MFA fallback | not configured |
| Admin/support tools | Tenant lookup, impersonation (audited), suspension | not configured |
| Logging/monitoring | Error capture, audit log of state changes | partial |
| Rate limiting | Per-tenant limits on external + internal calls | not configured |
| Scheduled jobs | Saved-search refresh, snapshot diffing | designed |
| Data-provider credentials | Per-tenant or platform-level API keys, secret-stored | not configured |
| Privacy/terms | Privacy policy, ToS, data processing agreement | not configured |
Every user-owned record (properties, notes, targets, field records, analyses, seller info, proposals, offers, documents, actual outcomes, acquisition history) MUST carry a tenantId and be filtered by it on every read/write.
Joseph migration: Joseph's existing localStorage data becomes a single private tenant during migration. No other tenant can read it.
Enforcement: Row-level security at the DB layer + application-level tenantId filter on all queries.
Shared data: Public parcel/CAMA geometry may be shared/cached across tenants (it is public record). Investor-specific intelligence (notes, offers, outcomes) is NEVER shared.
| Option | Cost | Isolation | Verified |
|---|---|---|---|
| Browser localStorage (CURRENT) | $0 | NONE — single implicit tenant | ✓ |
| IndexedDB (CURRENT for offline cache) | $0 | NONE | ✓ |
| Cloudflare D1 (SQLite at edge) | Free tier; paid ~$5/mo + usage | Row-level via tenantId column | UNVERIFIED |
| Supabase Postgres | Free tier; Pro ~$25/mo | RLS policies + auth.uid() | UNVERIFIED |
| Cloudflare KV / Workers KV | Free tier; paid ~$5/mo + reads/writes | Key prefix by tenantId | UNVERIFIED |
Current: Manual refresh only. User clicks RUN SEARCH; snapshot diff computes NEW/CHANGED/REMOVED.
Future: Scheduled job (cron/edge timer) runs each active saved search on a cadence, stores snapshot, diffs, and notifies.
Status: NOT CONFIGURED — architecture only
Commercial Cost Model by User Count
| Users | Database | Hosting | Maps | Property Data | Est. Total |
|---|---|---|---|---|---|
| 1 | $0 (localStorage) | $0 (edge free tier) | $0 (Esri/OSM free) | $0 (public GIS) | $0 |
| 25 | UNKNOWN (D1/Supabase tier) | UNKNOWN (edge limits) | UNKNOWN (tile usage) | $0 (public) or UNKNOWN (paid) | UNKNOWN — needs vendor quotes |
| 100 | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN — needs vendor quotes |
| 500 | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN — needs vendor quotes |
| 1000 | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN — needs vendor quotes |
All costs at 25+ users are UNKNOWN until vendor quotes obtained. No invented prices. At 1 user (current), verified cost = $0.
$97/Month Feasibility (Pricing Hypothesis)
$97/month is a PRICING HYPOTHESIS only — not hard-coded anywhere.
- • Cost-per-active-user must stay well below $97 to leave margin
- • Maps: free Esri/OSM tiles must cover Pro usage, OR a paid tier (Mapbox) must fit budget — UNKNOWN until usage measured
- • Geocoding: Census free tier covers low volume; paid geocoding needed at scale — cost UNKNOWN
- • Property data: $0 public GIS keeps cost near zero; paid enrichment (ATTOM/Regrid) would erode margin
- • Database + hosting: must stay on free/low tiers (D1/Supabase free → paid only at threshold)
- • Background jobs: platform cron at $0; scale cost UNKNOWN
Do NOT launch billing until cost-per-user is verified below the price point with margin.
Deal Tools & Documents Architecture
Workflow: Property → Deal Workspace → Calculators → Documents → Checklist → Offers → Closing → Outcomes
Native calculator translating N2W spreadsheet formulas into a tested engine. Must reuse acquisition-calc.ts primitives — NOT a competing engine. Requires golden-number regression before replacing spreadsheet.
Native calculator. Identify overlap with acquisition-calc.ts first; extend authoritative primitives rather than duplicating.
Native calculator. Overlap analysis + golden-number testing required before adoption.
Interactive digital checklist with statuses, notes, timestamps. Property/deal-specific instance — editing one transaction never modifies the master.
- • Every autofilled value carries provenance — never manufacture UNKNOWN info.
- • Autofill populates empty fields; it does NOT overwrite user-entered values.
- • If source field is UNKNOWN, autofill leaves the target empty with provenance 'unknown'.
- • Autofill writes into a deal-specific instance — never the master template.
No third-party/proprietary templates redistributed until ownership/license confirmed. Spreadsheet formulas require independent golden-number regression before replacing spreadsheets. acquisition-calc.ts remains the authoritative financial engine — no competing engine.
Commercial Rights / IP Register
| Asset | Kind | Owner | Internal | Commercial | Redist. |
|---|---|---|---|---|---|
| CT Statewide CAMA/Parcel | government dataset | State of Connecticut | internal use | commercial use unknown | commercial use unknown |
| NYS Tax Parcels Public | government dataset | State of New York | internal use | commercial use unknown | commercial use unknown |
| N2W Calculator v5.4 | spreadsheet template | UNVERIFIED | internal use | commercial use unknown | not permitted |
| AWS Calculator v10 | spreadsheet template | UNVERIFIED | internal use | commercial use unknown | not permitted |
| DASF v3.4 | spreadsheet template | UNVERIFIED | internal use | commercial use unknown | not permitted |
| ClosingDocsChecklist v3.0 | spreadsheet template | UNVERIFIED | internal use | commercial use unknown | not permitted |
| NYS Tax Parcels Public | government dataset | State of New York | internal use | commercial use unknown | commercial use unknown |
| NJ Parcels + MOD-IV Composite | government dataset | State of New Jersey | internal use | commercial use unknown | commercial use unknown |
| Ohio Statewide Parcels Public View | government dataset | State of Ohio | internal use | commercial use unknown | commercial use unknown |
| Florida Statewide Cadastral / FDOR | government dataset | State of Florida / County Property Appraisers | internal use | commercial use unknown | commercial use unknown |
State-by-State Source Register (Verified Sources)
Phase 1Q — Commercial Rights Gate (3 Independent Dimensions)
A technically LIVE endpoint does NOT automatically become SaaS-approved. Three independent dimensions: technical (reachable?), commercial use (may we use it in a commercial product?), redistribution (may we cache/transform/redistribute inside a paid SaaS?). Silence in a license is NEVER permission.
| State | Category | Provider | Technical | Commercial | Redist. | SaaS? |
|---|---|---|---|---|---|---|
| Connecticut | Parcel/CAMA | CT Statewide CAMA/Parcel (CT GIS Office / CT ECO) | 🟢 LIVE | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| New York | Parcel/CAMA | NYS Tax Parcels Public (FeatureServer layer 1) | 🟢 LIVE | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| New Jersey | Parcel/CAMA | NJ Parcels + MOD-IV Composite (Cadastral MapServer layer 0) | 🟢 LIVE | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| Ohio | Parcel/CAMA | Ohio Statewide Parcels Public View (FeatureServer layer 0) | 🟢 LIVE | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| Florida | Parcel/CAMA | Florida Statewide Cadastral / FDOR 2025 (FeatureServer layer 0) | 🟢 LIVE | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| Connecticut | Court/Foreclosure | CT Judicial Branch Civil Lookup | 🔵 RESEARCH ONLY | 🔴 NOT PERMITTED | 🔴 NOT PERMITTED | ⛔ NO |
| Connecticut | Probate | CT Probate Court Case Lookup | 🔵 RESEARCH ONLY | 🔴 NOT PERMITTED | 🔴 NOT PERMITTED | ⛔ NO |
| Connecticut | Tax Delinquency | Municipal Tax Collector Portals | 🔵 RESEARCH ONLY | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| Connecticut | Recorder/Land Records | Town Clerk RECORDhub / SearchIQ Index | 🔵 RESEARCH ONLY | 🔵 UNVERIFIED | 🔴 NOT PERMITTED | ⛔ NO |
| Connecticut | Code Enforcement | Bridgeport Anti-Blight / Stamford Code Enforcement | ⚫ NOT CONNECTED | 🔵 UNVERIFIED | 🔵 UNVERIFIED | ⛔ NO |
| All States | Listing/MLS | MLS / Zillow / Redfin / Realtor.com | ⚫ NOT CONNECTED | 🔴 NOT PERMITTED | 🔴 NOT PERMITTED | ⛔ NO |
Phase 1Q — Provider / Data Categories (8 Tracks)
Parcel/CAMA data is separated from investment intelligence. Public GIS gives geometry + assessment — it does NOT give equity, mortgage, foreclosure, listing, DOM, or vacancy. 1 of 8 categories operational (LIVE). The rest are RESEARCH_ONLY or NOT_CONNECTED.
Parcel geometry, APN, owner, mailing, assessment, appraisal, beds/baths, living area, sale history, land use.
Mortgages, releases, assignments, lis pendens, judgment liens, tax liens, mechanic's liens, deeds, probate deeds.
Foreclosure cases, filing date, case number, plaintiff, defendant, property address, case status, judgment/sale.
Delinquent real-estate taxes, outstanding balance, tax liens, tax-sale status, delinquency date.
Decedent estate cases, trusts, probate district, case status. Possible estate-match to property owner.
Active listings, listing price, DOM, price reductions, expired/withdrawn, pending, sold status.
Building violations, property-maintenance violations, zoning violations, unsafe structures, blight, open permits.
Vacancy signals, fire/insurance loss, water shut-off indicators, utility disconnects, other distress not covered above.
Phase 1Q — Property Data Freshness Architecture
| State | Category | Provider | Source Update Freq. | Verified? | ≤24h Detection? |
|---|---|---|---|---|---|
| Connecticut | parcel cama | CT GIS Office / CT ECO Statewide CAMA | Annual | ✅ Yes | ⛔ No |
| New York | parcel cama | NYS Tax Parcels Public (FeatureServer layer 1) | Annual | ✅ Yes | ⛔ No |
| New Jersey | parcel cama | NJ Parcels + MOD-IV Composite | Annual | ✅ Yes | ⛔ No |
| Ohio | parcel cama | OGRIP Statewide Parcels Public View | Annual | ✅ Yes | ⛔ No |
| Florida | parcel cama | FDOR Statewide Cadastral 2025 | Annual | ✅ Yes | ⛔ No |
| All States | court foreclosure | CT Judicial Branch (manual portal) | UNKNOWN | 🔵 No | ⛔ No |
| All States | tax delinquency | Municipal tax portals | UNKNOWN | 🔵 No | ⛔ No |
| All States | recorder land records | Town clerk / RECORDhub index | UNKNOWN | 🔵 No | ⛔ No |
| All States | probate | CT Probate Court Case Lookup | UNKNOWN | 🔵 No | ⛔ No |
| All States | listing mls | MLS / commercial portals | Daily | 🔵 No | ⛔ No |
| All States | code enforcement | Municipal code/blight datasets | UNKNOWN | 🔵 No | ⛔ No |
| All States | other distress events | Various | UNKNOWN | 🔵 No | ⛔ No |
Phase 1Q — Property Watch Architecture (DESIGN ONLY)
Detection target: Detection within 24 hours of the event becoming available from the authorized source — TARGET, not current guarantee.
Current capability: Manual snapshot diff exists for CT CAMA fields (watch-snapshots.ts). User must manually trigger REFRESH. No automated monitoring, no notifications.
- • Durable persistence for snapshots (cannot live in browser for automation)
- • Scheduled job runner (Cloudflare Cron Triggers or external scheduler)
- • Per-tenant rate limiting on public endpoints
- • Notification channel (email/in-app) — currently NONE
- • Commercial rights clearance for cached/redistributed data
- • Connected event sources (foreclosure, tax, liens, listings — all NOT_CONNECTED)
- • Owner name changed
- • Owner mailing address changed
- • Assessment changed
- • CAMA attributes updated
- • New foreclosure filing detected
- • Lis pendens recorded on property
- • Tax delinquency detected
- • Tax sale / auction notice filed
- • New lien recorded on property
- • New mortgage recorded
- • …and 9 more
Phase 1Q — Paid Provider Research (DOCUMENTATION ONLY — NOT PURCHASED)
Phase 1Q — Property Data Freshness Target Register
For each signal track: the authoritative source, verified source update frequency, our engineering target detection time, and what we actually achieve today. Target ≠ guarantee. SOURCE FRESHNESS ≠ PLATFORM POLLING FREQUENCY.
| Signal | Category | Authoritative Source | Source Freq. | Target | Actual Today | Automation | Technical |
|---|---|---|---|---|---|---|---|
| CAMA / Assessment Change | parcel cama | State GIS Office / County Property Appraiser | Annual | Within 24 hours | Manual only | Partial automation | 🟢 LIVE |
| Ownership / Deed Transfer (via CAMA) | parcel cama | State GIS Office (sourced from town/county recorder) | Annual | Within 24 hours | Manual only | Partial automation | 🟢 LIVE |
| Deed Recording / Ownership Transfer | recorder land records | Municipal Town Clerk / County Recorder | Daily | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Mortgage Recording | recorder land records | Municipal Town Clerk / County Recorder | Daily | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Lis Pendens / Pre-Foreclosure Notice | recorder land records | Municipal Town Clerk / County Recorder | Daily | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Judgment / Tax / Mechanic's Lien | recorder land records | Municipal Town Clerk / County Recorder | Daily | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Foreclosure Case Filing | court foreclosure | CT Judicial Branch | Daily | Within 24 hours | Manual only | Not permitted | 🔵 RESEARCH ONLY |
| Foreclosure Judgment / Sale Date | court foreclosure | CT Judicial Branch | Daily | Within 24 hours | Manual only | Not permitted | 🔵 RESEARCH ONLY |
| Tax Delinquency Detected | tax delinquency | Municipal Tax Collector | UNKNOWN | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Tax Sale / Auction Notice | tax delinquency | Municipal Tax Collector | UNKNOWN | Within 24 hours | Manual only | Manual only | 🔵 RESEARCH ONLY |
| Probate / Estate Case Filed | probate | CT Probate Courts | UNKNOWN | Within 24 hours | Manual only | Not permitted | 🔵 RESEARCH ONLY |
| New Listing / Price Change / Pending / Sold | listing mls | Regional Multiple Listing Service | Near real-time | Real-time | Not possible | Partial automation | ⚫ NOT CONNECTED |
| Code Violation / Blight / Condemnation | code enforcement | Municipal Building / Code Enforcement | UNKNOWN | Within 24 hours | Manual only | Manual only | ⚫ NOT CONNECTED |
| Vacancy Signal | other distress events | Various (utility, postal, assessor occupancy field) | UNKNOWN | Within 24 hours | UNKNOWN | UNKNOWN | ⚫ NOT CONNECTED |
Phase 1Q — Sources Required for ≤24h / Near-Real-Time Detection
What would need to be licensed + connected to hit the 24-hour detection target for the two highest-value event tracks. NONE purchased. NONE connected. All BLOCKED or conditional.
Phase 1Q — Property Watch Notification Architecture (DESIGN ONLY)
Target: Detect material property changes within 24 hours of the event becoming available from the authorized source — preferably much faster where legitimate near-real-time feeds permit.
- 1. Property saved → Watch enabled (per-tenant)
- 2. Scheduler triggers authorized-source check at cadence permitted by source rights
- 3. Current snapshot retrieved from connected provider
- 4. Snapshot compared with prior snapshot (compareSnapshots engine — already built)
- 5. Material change detected → PropertyWatchEvent created (already modeled)
- 6. Notification triggered via channel (email / in-app / SMS)
- 7. Event + provenance stored durably (per-tenant isolation)
- • Polling frequency must NEVER exceed what the source license permits.
- • Polling a DAILY source every minute does NOT make data real-time — it wastes rate-limit budget.
- • Recommended cadence = min(sourceUpdateFrequency, license-permitted frequency).
- • ANNUAL sources (CAMA) → poll weekly at most; detection bounded by annual updates.
- • DAILY sources (recorder/court) → poll daily IF a connected API exists (none today).
- • NEAR_REAL_TIME sources (MLS) → poll hourly IF MLS API connected + rights cleared.
- • Durable per-tenant persistence (snapshots cannot live in browser for automation)
- • Scheduled job runner (Cloudflare Cron Triggers or external scheduler)
- • Per-tenant rate limiting on public endpoints (respect source ToS)
- • Notification channel (email/in-app) — currently NONE configured
- • Commercial rights clearance for any cached/redistributed data
- • At least one connected event source (foreclosure/listing/tax/lien) — currently NONE
- • New foreclosure filing detected
- • Lis pendens recorded on property
- • Property listed for sale
- • Listing price reduced
- • Listing moved to pending
- • Property sold
- • New lien recorded
- • Ownership changed — deed recorded
- • Tax delinquency detected
- • Tax sale / auction notice filed
- • Probate case filed (possible estate match)
- • Assessment changed
- • Code violation recorded
- • Owner name changed
- • Owner mailing address changed
Phase 1R — Durable Persistence + Property Event Ledger
- • Cloudflare D1 (SQLite at the edge) — AVAILABLE BUT UNCONFIGURED. Free tier: Free tier: 5GB storage, 5M rows read/day, 100K rows written/day (per Cloudflare published limits — verify before relying). Binding configured: false. Survives restart/rebuild/redeploy: true (if configured).
- • Supabase Postgres — AVAILABLE BUT UNCONFIGURED. Free tier: Free tier: 500MB storage, paused after inactivity (per Supabase published limits — verify). Binding configured: false. Survives restart/rebuild/redeploy: true (if configured).
One ingestPropertyEvent() contract serves BOTH manual capture (today) and future automated feeds. Manual events default to UNVERIFIED. Deduplication is deterministic; conflicts are flagged, never silently merged. Event date, source publication date, and platform discovery date are three distinct timestamps.
10 localStorage structures inventoried (2 HIGH risk). Safe path: BACKUP → VALIDATE → MIGRATE → VERIFY. Migration is BLOCKED until a durable binding is configured + a restart/redeploy survival test passes. Local source is never erased automatically.
ARCHITECTURE ONLY. No providers are connected for any event signal track. Cannot measure provider performance without at least two connected providers producing the same signal type for the same coverage area. Future value: Lets Joseph compare providers on cost-per-useful-event and detection speed BEFORE purchasing — the evidence we need before paying for data.
Phase 1R — Durable Persistence Proof
NOT durable. localStorage is browser-only and does not survive server restart, rebuild, or redeploy. A durable binding (Cloudflare D1 or Supabase) is AVAILABLE but NOT configured. The Property Event Ledger uses the LocalStorageAdapter today so functionality works in-browser, but this is NOT production-durable persistence.
Limits: Free tier: 5GB storage, 5M rows read/day, 100K rows written/day (per Cloudflare published limits — verify before relying).
Runs in the Workers runtime this project targets. Requires a D1 binding in the deployment config (wrangler / nitro) + a database ID. NOT configured. Would need binding setup + a live restart/redeploy survival test before claiming durable.
Limits: Free tier: 500MB storage, paused after inactivity (per Supabase published limits — verify).
External hosted Postgres. Requires account + project + connection string stored as a secret. NOT configured. Adds an external dependency + potential future cost.
- 1. Create a Cloudflare D1 database and add a D1 binding to the deployment config (wrangler / nitro).
- 2. Store the database binding name so the runtime can inject it.
- 3. Implement a D1Adapter class implementing the PersistenceAdapter interface (read/write/remove/keys).
- 4. Swap getActiveAdapter() to return the D1Adapter when the binding is present.
- 5. Run a restart + redeploy survival test: write a record, restart/redeploy, read it back.
- 6. Only after survival is verified, mark PERSISTENCE_STATUS.durable = true.
- 7. Migrate existing localStorage data via the safe BACKUP → VALIDATE → MIGRATE → VERIFY path.
Phase 1R — Local Data Inventory & Migration Safety
- 1. BACKUP — export full app backup JSON (existing EXPORT APP BACKUP capability)
- 2. VALIDATE — validate backup schema + record counts + conflict identification
- 3. MIGRATE — copy (not move) records into the durable store using a fixture/copy first
- 4. VERIFY — read back from durable store + compare counts + spot-check relationships
- 5. ONLY THEN mark migration successful — never erase local source automatically
| Key | Description | Provenance fields |
|---|---|---|
| ctres.propertyStore.v1 | Core property records (manual + imported + enriched) | source, dataSource, retrievedAt, collectionYear |
| ctres.closedDeals.v2 | Consolidated acquisition store (analyses, proposals, offers, closed deals) | source, createdAt, updatedAt, discoverySource |
| ctres.fieldNotes.v1 | Field walk notes + photos + condition observations | createdAt, capturedAt |
| ctres.targets.v1 | Today's Targets work queue | addedAt, reason, sourceProvenance |
| ctres.reviewState.v1 | Property review status (unreviewed/reviewing/interesting/not-a-fit/target) | reviewedDate, sourceSearch |
| ctres.savedSearches.v1 | Saved searches + snapshots | createdAt, lastRun |
| ctres.watchSnapshots.v1 | Property watch snapshots (manual CAMA diff) | capturedAt, source |
| ctres.discoveryTrace.v1 | Discovery provenance (which search found which property) | discoveryDate, searchName, criteriaMatched |
| ctres.activityTimeline.v1 | Property activity timeline events | timestamp, source |
| ctres.propertyEvents.v1 | Phase 1R Property Event Ledger (NEW) | eventDate, discoveredAt, sourcePublishedAt, sourceProvider, sourceRecordId, captureMethod, verificationStatus |
Phase 1R — Property Event Ledger (Canonical)
A single provenance-preserving ledger for material property events. Both MANUAL verified events (today) and future AUTOMATED authorized feeds enter through the same ingestion contract — the manual workflow is simply one producer.
Manual entries default to UNVERIFIED unless Joseph explicitly sets VERIFIED. Automated feeds default to UNVERIFIED until a human confirms. Conflicting legal events are NEVER silently merged — flagged CONFLICTING for review.
- • eventDate — when the real-world event occurred
- • sourcePublishedAt — when the source made it available
- • discoveredAt — when our platform detected it
Enables future measurement of source lag, platform detection lag, and total event-to-detection lag — the evidence layer for evaluating paid data providers.
Phase 1R — Derived Opportunity Signals (Evidence-Based)
Events contribute to derived intelligence labels (PRE_FORECLOSURE, TAX_DISTRESS, etc.). Every signal carries its supporting events — never an opaque score. No AI scoring in Phase 1R. MULTIPLE_DISTRESS_SIGNALS activates when ≥2 distress categories are present.
Phase 1R — Provider Performance Benchmark (Architecture Only)
Intended use: Compare connected providers on the same signal track by source lag, platform detection lag, accuracy, duplicate rate, missing rate, and cost-per-useful-event — so Joseph can make evidence-based decisions BEFORE paying for data (e.g. 'Provider A costs $X but gets foreclosure events 18 hours earlier than B').
- • At least two connected providers for the same signal track (to compare)
- • Durable persistence to accumulate measurements across time
- • A meaningful sample of real events (not test data)
- • Verified cost data for each provider being compared
Phase 1R — Property Watch Prerequisite Update
The Property Event Ledger + ingestion contract are the foundation Property Watch will use when its prerequisites are met. Manual event capture is operational today; automated monitoring is not.
Phase 1S — Runtime Verification (Cloudflare Workers)
- • D1 is runtime-compatible (Workers binding) but NOT configured in this deployment.
- • No wrangler.toml, no d1_databases, no env var, no secret — confirmed by inspection.
- • A D1Adapter is implemented behind binding detection; it activates ONLY when detectD1Binding() finds a real bound D1Database.
- • Until a binding exists + a genuine restart/redeploy survival test passes, all lifecycle tests are UNVERIFIED_NOT_TESTABLE — never PASS.
- • Browser never receives DB credentials; all durable access goes through server functions (trust boundary).
Phase 1S — D1 Durable Adapter
ctres_kv (tenant_id, key, value, created_at, updated_at) + idx_ctres_kv_tenantActivation rule: Activates ONLY when detectD1Binding() finds a real bound D1Database. Never simulated. Never fake.
Phase 1S — Real Persistence Lifecycle Test
| Lifecycle event | Result |
|---|---|
| Refresh (write + read-back) | UNVERIFIED NOT TESTABLE |
| Runtime/server restart | UNVERIFIED NOT TESTABLE |
| Rebuild | UNVERIFIED NOT TESTABLE |
| Redeployment | UNVERIFIED NOT TESTABLE |
| Cross-browser / cross-device | UNVERIFIED NOT TESTABLE |
- • No durable backend configured in this deployment (no Postgres/Supabase secrets, no D1 binding). The lifecycle harness is implemented as server functions (writeLifecycleTest / readLifecycleTest) and will produce VERIFIED_PASS only after a real backend is configured + a genuine restart/redeploy is performed and readLifecycleTest is re-run.
- • Mocks, unit tests, in-memory DBs, localStorage, and simulated adapters do NOT count.
Phase 1S — Reversible Migration Harness
Safe path: BACKUP → INVENTORY → VALIDATE → DRY RUN → MIGRATE → VERIFY → RECONCILE. localStorage is never deleted after migration; rollback remains available. Production read path does not switch until verification succeeds.
Dry-run requires no binding; real migration is BLOCKED until a D1 binding is configured.
Phase 1S — Property Watch Prerequisite Update
- • Durable persistence NOT proven — D1Adapter implemented but no D1 binding configured (Phase 1S)
- • No scheduler
- • No notification infrastructure
- • No connected distress/event providers (all RESEARCH_ONLY or NOT_CONNECTED)
- • Commercial redistribution rights UNVERIFIED for all sources
Phase 1T — D1 Activation Status (BLOCKED: infrastructure action required)
| Lifecycle event | Result |
|---|---|
| Refresh (write + read-back) | UNVERIFIED NOT TESTABLE |
| Runtime/server restart | UNVERIFIED NOT TESTABLE |
| Rebuild | UNVERIFIED NOT TESTABLE |
| Redeployment | UNVERIFIED NOT TESTABLE |
| Cross-browser / cross-device | UNVERIFIED NOT TESTABLE |
Phase 1T — Server-Controlled Single-Tenant Context
The server determines Joseph's tenant context. Client-supplied tenantId is ignored for writes and cannot be used to read another tenant's data. This is NOT full multi-tenant authentication — it is a server-controlled single-tenant trust boundary appropriate to the current single-user MVP.
tenant.josephEnforcement: enforceTenant() coerces any client-supplied tenantId to the server-controlled tenant before every durable read/write. A client cannot read/write another tenant by changing tenantId. Tests prove substitution is rejected.
Phase 1T — Infrastructure Action Joseph Must Perform
- In the Cloudflare dashboard, create a D1 database (free tier — $0). Name it e.g.
ctres-acquisition. - Add a D1 binding to the deployed Worker. Binding name expected by the app:
DB(also checksD1,DATABASE,CTRES_DB). The binding must be present in the Worker's environment. - Redeploy the Worker so the binding is injected into the runtime.
- Tell Mak the binding is live. Mak will run
writeLifecycleTest(writes a canary to real D1), then trigger a redeploy, then runreadLifecycleTestto prove the same record survived. - Only after survival is VERIFIED_PASS will Mak run the safe migration (BACKUP → VALIDATE → DRY RUN → MIGRATE → VERIFY → RECONCILE) and switch the authoritative read path to D1. localStorage is retained as rollback.
No payment, no paid upgrade, no recurring charge required — D1 free tier covers the MVP. Do not enter billing information for a paid plan without explicit approval.