Pull to refresh

System Architecture & Documentation

Reference guide for LandConnect data, outreach, and operational accountability.

Table of Contents

  1. PropertyInsightsCard
  2. EnhancedLeviAnalysis
  3. Lead Detail Page Layout
  4. Deal Detail Page Overview
  5. n8n Workflow Integration
  6. Branding & Data Source Disclosure
  7. SMS Campaign System (Acquisition Control)

1) PropertyInsightsCard

File: components/leads/PropertyInsightsCard.jsx

What it displays

  • Always renders grouped sections from top-level columns in enhanced_deal_analysis:
    • OWNERSHIP: owner_name, ownership_months (converted to years), is_absentee, is_distressed
    • TAX & LIENS: tax_assessed_value, tax_delinquent, lien_count
    • SALE HISTORY: last_sale_date, last_sale_price, previous_listing_price, previous_listing_dom
    • VALUATION: estimated_market_value, price_per_acre, lot_size_acres, asking_price
  • If propertyreach_raw (JSONB) exists, it expands with additional sections using exact camelCase fields from the raw object:
    • PROPERTY DETAILS: apn, landUse, bedrooms, bathrooms, rooms, stories, squareFeet, groundFloorSqft, lotAcres, lotSquareFeet, yearBuilt, pool, deck, hoa, hoaType, vacant, airConditioning, garage/garageUnits, appliances (array)
    • LOCATION: fullAddress, city, state, zip, county, fips, latitude, longitude (shown as GPS), floodZone
    • OWNER DETAILS: contacts[] → name, age, gender, education, occupation, language, phones, emails, mailingAddress
    • FINANCIAL: assessedImprovement, marketImprovement, linkedEstimate, pricePerSqFt, estimatedEquity (shown as percent)
    • SALE & LISTING: lastSaleDate, lastSalePrice, loanRecording, priorPurchaseMethod, listingDate/status/type/price
    • LINKED PROPERTIES: linkedProperties count, linkedVacant count
  • Formatting: currency values show as $ with commas, dates are human-readable, booleans display as Yes/No badges, GPS as decimal coordinates, arrays comma-separated.

Data source & fetching

  • Reads from Supabase view/table enhanced_deal_analysis via supabaseProxy using: viewName = enhanced_deal_analysis?lead_id=eq.${leadId}&order=analyzed_at.desc&limit=1 (schema: public).
  • Primary fields come from individual columns; optional propertyreach_raw JSONB is parsed when present for expanded view.
  • Hidden entirely if no record is returned for the lead.

Placement

  • Rendered on Lead Detail immediately after Quick Actions.

2) EnhancedLeviAnalysis

File: components/leads/EnhancedLeviAnalysis.jsx

  • Sections shown: Property & Valuation, Risk Assessment, Pricing Strategy, Scorecard, Due Diligence, Analyst Notes.
  • Change: The previous “PROPERTYREACH ENRICHMENT DATA” accordion (and its empty-state message) was removed. All enrichment now lives in PropertyInsightsCard.

3) Lead Detail Page Layout Order

File: pages/LeadDetail.jsx

  1. Property Images
  2. Quick Actions
  3. Property Insights Card (this new card)
  4. Quick Links
  5. Deal Score (DealSnapshotStrip)
  6. Quick Stats
  7. LEVI Analysis
  8. Lead Information

4) Deal Detail Page Overview

File: pages/DealDetails.jsx (overview)

  • Consolidated dashboard for a single deal with tabs for Acquisition, Disposition, Financials, Due Diligence, and AI-driven Intelligence.
  • Shows property imagery/maps, enhanced analysis (LEVI), risk & valuation metrics, comparable sales, exit strategies, and collaborative artifacts (contacts, documents, timeline, notes).
  • Pulls enriched data and KPIs from Supabase mirrors and Base44 entities, surfacing current stage and calculated KPIs.

5) n8n Workflow Integration

  • The GPT Agent Land Deal Processor (n8n) writes the full PropertyReach API payload to enhanced_deal_analysis.propertyreach_raw (JSONB) via Supabase.
  • Older analyses may have propertyreach_raw = NULL; on new runs it is populated. When present, PropertyInsightsCard automatically expands to display detailed sections backed by raw fields.

6) Branding & Data Source Disclosure

  • End-user UI intentionally hides third-party branding. The card header reads “Property Insights” with no source attributions.
  • References to the underlying data provider are internal-only within documentation and code comments.

7) SMS Campaign System (Acquisition Control)

Page: pages/AcquisitionControl.jsx

Architecture Overview

Acquisition Control groups Upload, Campaigns, Lists, Quick Send and Follow-ups in one workspace. Quick Send uses the existing manual send route. Follow-ups exposes the scheduled queue. The modes have explicit names and metrics; a count from one mode must not be presented as another mode's count.

Entities

  • SMSCampaign (entities/SMSCampaign.json): Stores campaign metadata (name, status, schedule, send counts). Status lifecycle: draft → scheduled → sending → completed/paused. RLS restricted to admin/staff/owner/programmer roles.
  • LeadList (entities/LeadList.json): Represents an imported CSV file. Links to a campaign via campaign_id. The batch_id field matches the base44_id on Lead records for filtering. Status lifecycle: uploaded → mapped → ready → sending → sent.
  • Lead (existing): CSV-imported leads are tagged with source='csv_import' and base44_id=<batch_id>. The batch_id is generated from the list label + timestamp.

Components

  • components/acquisition/UploadListsTab.jsx — Multi-file CSV upload with column auto-mapping, label editing, and batch import. Creates LeadList records on import.
  • components/acquisition/CampaignsTab.jsx — Campaign CRUD, list assignment modal, schedule modal, Send Now with real-time progress, Pause/Resume.
  • components/acquisition/ListsTab.jsx — List table with assign-to-campaign, direct send, and delete actions.
  • components/acquisition/QuickSendTab.jsx — Manual batch send using Supabase-backed countEligibleLeads and getEligibleLeads backend functions.
  • components/acquisition/SMSProgressBar.jsx — Reusable progress bar showing sent/success/failed counts.

Campaign/List Delivery Flow

  1. Leads are fetched from Base44 Lead entity filtered by base44_id = batch_id and status = 'new'.
  2. For each lead, a randomized message is generated using the lead's city/county.
  3. Message is POSTed to https://n8n.srv1251391.hstgr.cloud/webhook/send-sms-manual with {phone, message, leadId}.
  4. On success, the Lead record is updated: status → 'contacted', last_contact_at → now().
  5. Campaign/List entity records are updated with final send counts and status.

Access Control

The page checks user.role against ['admin', 'staff', 'owner', 'programmer']. Unauthorized users see a "Access Denied" screen. Both entities have matching RLS rules.

Quick Send: one audience definition

countEligibleLeads calls getEligibleLeads in count-only mode. Both normalize valid U.S. numbers to ten digits, exclude any existing conversation and deduplicate recipients. The count means uncontacted candidates before per-send checks, not verified delivery or scheduled-service eligibility. The old 1,147 versus 802 discrepancy came from separate outbound-only and any-conversation queries; those historical definitions have been reconciled.

Quick Send rechecks each lead through fetchLeadById and invokes sendLeadSMS with category manual. The existing n8n send-sms-manual route forwards through TextMagic using linked Twilio BYOC. Sender ending 3109 was verified on September 11. TextMagic-owned number inventory alone is not a valid sender check. A fixed message with the lead's city/county is previewed before starting; random claims about driving through the area are removed.

Phil authorized one original Quick Send batch of up to 100 total recipients and waived immediate human coverage acceptance as a launch prerequisite. Use one operator, keep the page open during manual requests and reconcile previous attempts before starting. Existing DNC/opt-out controls apply. Success responses, provider acceptance and delivery are separate facts. The interface shows request outcomes; provider receipts must establish delivery.

Follow-ups: scheduled queue

Follow-ups opens scheduledSmsOperations in the same workspace. Its prg_csuite queue retains its own mobile-verification, permission-evidence, timing, duplicate and daily/monthly controls. Those stricter scheduled checks are not the original Quick Send candidate definition. Do not silently move Phil's manual batch to this queue. Server-side scheduling does not depend on keeping this tab open.

One coordination record and quiet reporting

The PRG Executive Agent Control Tower is the coordination record. Supabase and provider receipts remain authoritative for business events. W-006 owns the one-time send, W-007 owns reply handling, and W-008 owns technical repair. Each item has one accountable coordinator, a current next action and evidence. Requested ownership, accepted ownership and completed work are distinct states.

Operational routines must not post in #staff, send staff DMs or repeatedly mention staff. Update existing Control Tower records and consolidate operational reporting to Phil in ChatGPT. Read current Operating Rules before historical notes. Keep paused specialists paused; do not create duplicate coordinators or send batches. The existing Morning Motivation announcement is a separate communication.

Inbound handling must be verified through saved receipt, lead association, owner notification and unresolved-reply tracking. Dan and Stephanie were requested as coordinator/backup but acceptance is not established. Escalate gaps to Phil in ChatGPT without delaying the authorized batch solely for immediate coverage. Code build success does not verify published UI, authenticated execution or actual delivery.

CMO Affiliate Growth Control Tower

The CMO orchestrator owns affiliate-growth coordination through CMOOutreachCampaign, CMOProspect and CMOOutreachTask. Automated collection may discover public group owners, moderators, creators, REIA leaders and public business contact routes; it must deduplicate by canonical profile/group/channel URL plus normalized contact, record the source and permission basis, score fit, and stop on suppression or opt-out.

The CMO team is Scout → Qualifier → Copy → Compliance → Outreach Coordinator → Reply Triage → Affiliate Success. The orchestrator must create one task per stage with an idempotency key, maintain campaign caps, and report researched, qualified, drafted, approved, contacted, replied, applied, converted, suppressed and failed counts by campaign and platform.

Email is the approved outbound rail for affiliate opportunity requests when a public business email or existing permitted contact is available. The email agent may generate a personalized draft from verified prospect facts and send only an approved CMOOutreachTask. Facebook and YouTube messages/comments remain human-approved platform actions. No bulk scraping, private-member collection, automated unsolicited DMs, income guarantees, or fabricated audience/KPI claims.

A response pauses follow-up and creates reply-triage work. An opt-out suppresses the prospect. Affiliate applications, referral events, commissions and payouts remain in the existing Affiliate/Referral/Commission system of record. The CMO dashboard must use stored records only; synthetic or random metrics are prohibited. Escalate blocked sends, repeated failures, complaints, or attribution conflicts to Phil in ChatGPT.