ADR-019: Magic Import

Status: Accepted Owner: @bilal Date: 2026-03-01

Context

Landlords migrating to Envo typically have property and tenant data in spreadsheets. Manual entry of 50–200+ properties is the primary adoption barrier in proptech. We need a bulk import feature that serves both tech-savvy users (exact template matching) and non-technical users (AI-assisted column mapping).

Decision

Implement a dual-mode import system with two paths:

1. Template Import (no AI)

  • Download a pre-formatted CSV template
  • Fill in data, upload
  • Exact + alias column matching (e.g., “post code” → “postcode”, “telephone” → “phone”)
  • Zero AI cost, instant processing

2. Magic Import (Claude-powered)

  • Upload any spreadsheet (CSV/Excel)
  • Claude Sonnet infers column mappings from headers + sample rows
  • Animated agent flow (Gathering → Planning → Reasoning → Synthesising)
  • User reviews and adjusts mappings before import
  • ~$0.002/request, 1–2s latency

Architecture

ComponentTechnologyRationale
File parsingxlsx (SheetJS) client-sideAlready installed; 500 rows trivial client-side
Column mapping (template)Alias lookup tableZero latency, deterministic
Column mapping (magic)Claude Sonnet via REST APIGood semantic understanding at low cost
Batch insertREST API + createMany()Single INSERT statement, ~100x faster than individual creates
ValidationZod schemas (shared client/server)Re-validation server-side for security

Integration Points

  • Onboarding: Optional step 3 (Details → Plan → Import)
  • Properties page: Import button in header + empty state CTA
  • Tenants page: Same pattern as properties

Two-File Import (Properties + Tenants)

  1. Import properties first → receive address→propertyId map
  2. Use map to resolve propertyId in tenant rows
  3. Import tenants with resolved IDs

Scaling Path

PhaseScaleApproach
v1 (current)≤500 rowsClient-side parsing, single batch insert
v2≤3,000 rowsChunked processing (500-row batches), progress bar
v3≤10,000 rowsBackground jobs (queue + worker), email notification on completion

Connector Framework

A connector interface is scaffolded for future integrations:

  • v1: Google Sheets (stub)
  • v2: Google Sheets (OAuth flow), Rightmove export
  • v3: API-based connectors (property management systems)

Consequences

Positive

  • Reduces onboarding friction from hours to minutes
  • AI mapping handles non-standard spreadsheets gracefully
  • Template mode works offline (no AI dependency)
  • Connector framework enables future integration growth

Negative

  • Magic import requires ANTHROPIC_API_KEY (falls back to template mode)
  • 500-row limit may frustrate large operators (addressed in v2/v3)
  • Client-side xlsx adds ~200KB to bundle (already installed for other features)

Risks

  • AI mapping quality depends on column naming — mitigated by user review step
  • Large batch inserts could timeout — mitigated by 500-row limit and chunking roadmap

Alternatives Considered

  1. Server-side file upload: More complex, requires file storage; 500 rows is trivial client-side
  2. GraphQL mutations for batch: Field selection adds overhead for bulk ops; REST is simpler
  3. Streaming insert (row-by-row): ~100x slower than createMany(); no benefit at this scale