Delivered remotely for a business based in Vancouver, Canada. Names withheld by agreement.
Project Overview
Industry: Real estate acquisition and outbound field sales.
Type of solution: A multi-tenant SaaS field-operations and CRM platform: a REST API and web back office serving multiple independent business customers, plus a mobile application for field agents.
Business context: An acquisition business buys lists of property leads, assigns them to canvassing agents, and sends those agents into neighbourhoods to knock on doors. What comes back determines everything downstream — which properties get followed up, which owners get nurtured, which deals get pursued. Historically this loop runs on spreadsheets and paper. Lists are re-keyed by hand, visits are self-reported and unverifiable, doorstep conversations are recorded as free text or not at all, and the pipeline beyond the first conversation lives in whatever system each team improvised.
General users: Field canvassing agents, team managers and business owners, acquisition and closing staff, and platform administrators — across multiple independent tenant businesses on a shared platform.
General purpose: To make field canvassing measurable. Get lists in without re-keying, get agents to the right doors, capture what happened at each one as structured and verifiable data, and carry the leads that matter through the rest of the acquisition process without losing the trail.
The Business Challenge
Every list arrives in a different shape. Lead lists come from multiple providers, and no two use the same columns, the same headers or the same conventions. Manual re-keying is slow, error-prone and loses the columns nobody had time to transcribe.
Every customer wants a different data model. One business tracks fields another does not care about, uses its own status vocabulary and wants its list views ordered its own way. Serving that with a code change per customer does not scale past a handful of tenants.
Field activity is unverifiable by default. "Nobody answered" is a claim that cannot be checked. When agent performance and compensation are tied to activity volume, an unverifiable activity log is a management problem, not just a reporting gap.
The doorstep conversation is the product. What the owner said — their intent, their timeline, the condition of the property — is the entire value of the visit. Captured as free text in a notebook, it cannot be searched, reported on or acted upon by anyone else.
A lead changes shape as it progresses. A property that goes somewhere passes through follow-up, nurture marketing, purchase discussion and closed deal. Each stage has different fields, a different audience and different reporting, but all of it has to remain traceable back to the original record.
Field conditions are hostile to software. Agents are outdoors, on foot, on mobile data, with the camera and continuous location running. Anything that demands a fast connection or a long form will not be used.
Reporting has to answer management's actual questions. Not "how many records exist" but how many doors were knocked, by whom, on which day, with what outcome, and what commission that generated.
Our Approach
Make import a configuration exercise, not a transcription exercise. We built a spreadsheet import wizard where the tenant maps each source column to a platform field once. The mapping is saved as a reusable template, and columns that do not correspond to an existing field can be promoted into tenant-defined custom fields rather than discarded. The next list from the same provider imports against the same template.
Push the data model into configuration. Custom field definitions, statuses, types, list column ordering and per-stage view layouts are all tenant-scoped configuration data. A new customer with an unusual field set is an afternoon of setup, not a release.
Provision new tenants from working defaults. Creating a tenant clones the platform's default statuses, activity events and default field set into tenant-scoped records, so a new customer starts with a functioning configuration instead of an empty screen.
Verify field visits on the device, and keep the evidence. When an agent logs a doorstep outcome, the application captures the device's current position, computes the distance to the property's stored coordinates locally, and records the outcome together with both coordinate pairs, the computed distance and a verification flag. Computing locally keeps logging fast in poor connectivity; storing the underlying measurements rather than only the verdict means the verification rule can be reviewed later without re-collecting data.
Structure the doorstep conversation. A questionnaire defined per tenant is instantiated against each lead and presented to the agent at the door, so the conversation produces structured, reportable answers rather than prose.
Model the pipeline as distinct stages with a preserved trail. Follow-up, nurture marketing, purchase and closed deal each have their own record, their own configurable field layer and their own list view, with explicit promotion between stages and the link back to the originating lead intact throughout.
Audit at two levels, for two audiences. Machine-readable change records — before, after, who, when, from where — are captured automatically at model level for compliance and dispute resolution. Separately, a declarative history engine translates field-level changes into a readable activity timeline for the people using the product.
Build the field app for the field. Map and list views of assigned work, local distance computation, photo capture, offline-tolerant local preferences, in-app charts and PDF training material — built as a focused agent tool rather than a mobile port of the back office.
The Solution
Spreadsheet import with reusable column mapping. Lists of any layout are imported through a mapping wizard, with saved templates for repeat imports and on-the-fly creation of custom fields for unmapped columns.
Tenant-configurable data model. Custom fields, statuses, types, default column ordering, per-stage view layouts and pagination preferences, all scoped per tenant and configured from the web back office.
Map-based territory work. Field agents see all leads and their own assigned leads in both list and map form, with per-property markers, detail callouts and live position tracking.
Proximity-verified visit logging. Every doorstep outcome is recorded with the device's position, the property's position, the computed distance between them and a verification flag — turning a self-reported claim into a measured one.
Configurable doorstep questionnaire. A per-tenant question set is attached to each lead and answered in the field, producing structured, reportable data from every conversation.
Photo capture and media attachment. Property photographs taken in the field are cropped and uploaded against the lead record.
Appointment scheduling with calendar and SMS. Appointments are created against a lead, synchronised to a calendar service with the external event reference stored so later edits update rather than duplicate, and reinforced with SMS and email reminders.
Multi-stage acquisition pipeline. Leads are promoted through follow-up, nurture marketing, purchase and closed-deal stages, each with its own configurable field set, list view and export, and each traceable back to the original lead.
Marketing automation. Campaigns, segments, tags and templates managed in the platform and synchronised with an email marketing service, so a lead that is not ready today can be nurtured until it is.
Commission and performance tracking. Configurable activity events per tenant, agent commission records with spreadsheet import, and commission reporting available to both managers and agents in the field app.
Reporting and dashboards. Visit statistics by day, by status, by type and by agent; team performance views; status-history reporting; and in-app charts for agents, with CSV and spreadsheet export across every list.
Agent training. Per-tenant training scripts distributed as documents and read inside the mobile application.
Full change auditing. Every meaningful record change is captured with actor, timestamp, origin and before/after values, alongside a readable activity timeline on each lead.
Key Features
Reusable column-mapping import Spreadsheet lists of any layout are mapped to platform fields once, saved as a template, and reused for subsequent imports — with unmapped columns promotable to tenant custom fields rather than lost.
Tenant-configurable schema and views Custom fields, statuses, types and list column layouts are configuration data scoped per tenant, across the core lead record and every pipeline stage independently.
Proximity-verified field visits Doorstep outcomes are logged with the device position, the property position, the computed distance and a verification flag, all persisted — evidence rather than assertion.
Configurable doorstep questionnaire A per-tenant question set instantiated against each lead, turning the conversation at the door into structured, searchable, reportable data.
Map-driven territory work Assigned and unassigned leads rendered as map markers with detail callouts and live agent position, so the agent's route is driven by the data rather than a printed list.
Multi-stage pipeline with per-stage configuration Follow-up, nurture, purchase and closed-deal stages, each with its own field layer, view configuration and exports, with explicit promotion and a preserved link to the originating lead.
Calendar and SMS-backed appointments Appointments synchronised to an external calendar with the event reference retained for clean updates, plus SMS and email reminders.
Marketing automation integration Campaign, segment and tag management synchronised with an email marketing service, so leads that are not ready are nurtured rather than dropped.
Dual-layer auditing Machine-readable change records with actor, timestamp and origin for compliance, alongside a human-readable activity timeline generated declaratively from field-level changes.
Activity and commission reporting Visit statistics by day, status, type and agent; team performance views; and commission tracking with spreadsheet import — visible in the back office and in the field app.
Technical Architecture
Mobile client. A React Native application for field agents, structured as feature modules with their own actions and reducers over a Redux store, and a singleton HTTP service layer. Screens cover lead lists and maps, visit logging with the doorstep questionnaire, appointment creation and execution, a calendar, in-app charts, commission reporting and a document viewer for training material. Device capabilities include continuous geolocation, map rendering with markers and callouts, camera capture with cropping, and local key/value storage for session and last-known-position state. Distance calculation for visit verification runs on the device.
API layer. A token-authenticated REST API. A shared base controller detects request audience from the URL and switches response shaping between JSON resource collections and server-rendered views, allowing one controller path to serve the mobile client, the web back office and its AJAX table views. Authentication middleware resolves the caller and injects identity, tenant and role onto the request for downstream use.
Web back office. A server-rendered tenant portal covering lead management, the import wizard, field and view configuration, every pipeline stage, campaigns, commissions, training material, reporting and exports — with an administrative layer above it for platform-level management.
Multi-tenancy. Tenant scoping is applied inside model query construction across the data model, with tenant provisioning cloning platform default configuration into tenant-scoped records.
Auditing layer. A model trait captures before/after change records with actor, IP and user agent. A separate declarative history library maps field changes to readable timeline entries through a configurable trigger map.
Data layer. A relational database evolved through a long migration history, with a dedicated indexing pass across the lead, activity-history, user and pipeline tables, model-level query caching on the highest-traffic reads, and soft deletes throughout so records remain recoverable.
Batch layer. Console-driven batch processing for bulk activity imports, operating in bounded batches rather than in a single pass.
Delivery. Deployment automated through a CI pipeline driving a scripted release process with atomic releases, retained rollback history and shared linked configuration and upload directories.
Flow: Mobile field app → Token-authenticated API → Tenant-scoped domain layer → Relational database with auditing → Web back office and reporting → Calendar, SMS, email and marketing automation services
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Database | MySQL with Doctrine DBAL, long migration history |
| Web back office | Server-rendered Blade views with an admin scaffolding layer |
| Query caching | Model-level caching layer |
| Change auditing | Model-level auditing package with a custom actor resolver |
| Import / export | Spreadsheet import and export library plus a bundled XLSX reader |
| Documents | PDF generation and PDF-to-image conversion |
| Calendar integration | Google Calendar via the Google API client |
| SMS | Twilio |
| Transactional email | SendGrid, with additional mail driver configuration |
| Marketing automation | Email marketing service integration for lists, segments and campaigns |
| API concerns | CORS handling, trusted proxies, request throttling, Guzzle HTTP client |
| Deployment | CircleCI pipeline driving scripted atomic releases |
| Mobile framework | React Native with React 17 |
| Mobile state | Redux with thunk middleware; Axios service layer |
| Mobile navigation | React Navigation (switch, stack and drawer navigators) |
| Mobile UI | NativeBase component library with a custom theme |
| Mobile mapping | React Native Maps with the Google provider; geolocation service |
| Mobile geospatial | Haversine and geolib for on-device distance and radius calculation |
| Mobile media | Image picker with cropping; blob handling; PDF viewer |
| Mobile reporting | React Native SVG and SVG chart components |
| Mobile storage | Local key/value preference storage; device info |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| Lead lists arriving in a different column layout from every provider and every tenant | A mapping wizard that pairs source columns to platform fields once and saves the result as a reusable template, with unmapped columns promotable to tenant custom fields rather than discarded — so the second import from a provider is a single step. |
| Every tenant wanting a different data model without a release per customer | Custom fields, statuses, types and list view layouts implemented as tenant-scoped configuration data across the core record and each pipeline stage independently, with new tenants provisioned by cloning platform defaults into working configuration. |
| Field visits being self-reported and unverifiable | Device position captured at logging time, distance to the property computed on the handset, and the outcome persisted together with both coordinate pairs, the computed distance and a verification flag — keeping the evidence, not just the verdict, so the rule can be reviewed without re-collecting data. |
| Doorstep conversations producing unusable free text | A per-tenant question set instantiated against each lead and answered in the field, so every visit yields structured, searchable answers that reporting can operate on. |
| One record needing a different shape at each pipeline stage | Distinct stage records, each with its own configurable field layer and list view, connected by explicit promotion and a retained link to the originating lead, so the trail survives the change in shape. |
| Two different audiences needing two different kinds of history | Machine-readable change auditing applied as a model trait — actor, origin, before and after — for compliance and dispute resolution, alongside a declarative history engine that renders field changes as a readable activity timeline for end users. |
| Reporting over an activity history that grows with every interaction | A dedicated indexing pass across the activity-history, lead, user and pipeline tables, model-level caching on the reference data that every report joins against, and chunked export paths with configurable batch sizes. |
| Appointments that must stay consistent with an external calendar | The external calendar event reference is persisted onto the appointment record, so subsequent edits and cancellations update or remove the existing entry instead of accumulating duplicates. |
| A mobile application used outdoors on unreliable connections | On-device distance computation rather than a server round trip, paginated list handling, local preference storage for session and last-known position, and a screen set scoped to what an agent actually needs at a door. |
Security & Reliability
Authenticated access with resolved identity. Mobile clients authenticate with a per-user token resolved server side; the web back office uses session authentication. In both cases the middleware resolves the caller and injects identity, tenant and role onto the request, so downstream code operates on a verified context rather than client-supplied values.
Tenant isolation. Tenant scoping is applied within model query construction across the data model, so one customer's leads, agents, configuration and reporting remain separate from another's on shared infrastructure.
Role separation. Distinct user groups for platform administration, business ownership, management and field agents, with privileged operations gated by role and one privileged role subject to a per-tenant quota.
Comprehensive change auditing. Record changes are captured with the acting user, timestamp, originating address and client, and full before/after values — providing an evidence trail for both compliance questions and internal disputes about what changed and when.
Recoverable deletion. Soft deletes are used throughout, so removal is reversible and history is not destroyed by an accidental action.
Verifiable field records. Visit records retain the underlying location measurements alongside the verification outcome, so an activity record can be examined rather than simply trusted.
Cross-origin controls and request throttling. Explicit policy over which clients may call the API, with rate limiting applied to API traffic.
Automated, reversible deployment. Releases are deployed through a CI-driven scripted process with atomic release directories and retained history, so a bad release can be rolled back rather than repaired in place.
Scalability & Performance
Cached reference reads. Statuses, types, custom field definitions and other reference data are read on nearly every list, map and report and change rarely — making them the right candidates for model-level caching.
Deliberate indexing. A dedicated indexing pass covers the activity-history, lead, user, configuration and pipeline tables, targeting the join and filter paths that reporting and list views actually use.
Bounded batch processing. Bulk activity imports run as console-driven batches with a fixed batch size rather than as a single large operation, keeping memory use predictable.
Chunked exports. Export paths read in configurable chunks with a separate export page size, so a large export does not translate into a single unbounded query.
Configurable pagination. Server-side pagination with a platform default and per-tenant overrides, so list endpoints return bounded result sets regardless of dataset size.
Client-side geospatial computation. Distance calculation for visit verification runs on the device, removing a network round trip from the most latency-sensitive action in the product and keeping it usable on poor connections.
Paginated mobile lists. The field application loads leads through paginated list handling with incremental fetching, so a large territory does not have to be loaded before the agent can start work.
Business Outcomes
- Lead lists are imported rather than re-keyed, with a saved mapping per provider that makes repeat imports a single step and stops unmapped columns from being silently lost.
- New tenants can be onboarded without engineering work, because fields, statuses and views are configuration and new tenants start from cloned working defaults.
- Field activity became measurable and reviewable, with each visit carrying its own location evidence rather than resting on self-report.
- Doorstep conversations became data, captured through a configurable question set that reporting, follow-up and marketing can all act on.
- The pipeline beyond the first conversation is tracked in one place, with each stage configured to its own needs and every record traceable back to the original lead.
- Managers can answer activity questions directly, through visit statistics by day, status, type and agent, team performance views and commission reporting.
- Changes are accountable, with a machine-readable audit trail for compliance and a readable activity timeline for everyday use.
- Agents work from a map instead of a printout, with their assigned properties, the questionnaire, photo capture, appointments and training material in one application.
Why it worked
Field software fails for a predictable reason: it is designed for the manager and used by the agent. If logging a doorstep outcome takes longer than writing it on a printed sheet, the printed sheet wins, and every dashboard built on top of the data becomes fiction. The design constraint is not "capture more" — it is "capture more while taking less time than the paper it replaces."
Our team builds for that constraint. We moved the verification computation onto the device so the agent is not waiting on a network at somebody's front door. We made the doorstep questionnaire configurable so each business asks its own questions rather than filling in fields that mean nothing to them. We made the import a mapping exercise the customer performs once instead of a transcription exercise they perform forever. And we kept the underlying measurements behind every verified visit, because a system that stores only a verdict cannot answer questions about the verdict later.
We also took multi-tenancy seriously where it counts — in the data model. Customer-specific fields, statuses, pipeline stages and list views are configuration, provisioned from working defaults when a tenant is created. That is what makes a platform something you can sell to the next customer rather than something you fork for them.
Our teams work across Laravel and modern PHP, multi-tenant SaaS architecture, mobile applications with heavy device-capability use, third-party integration for calendar, messaging and marketing automation, and reporting over large operational datasets — with the judgement to know which parts of a field process must be modelled faithfully and which will be abandoned by the people expected to use them.
Final Summary
An acquisition team buys a list, hands it to agents, and sends them out to knock doors. Until recently that loop ran on spreadsheets and printouts: lists re-keyed by hand, visits self-reported, doorstep conversations recorded in a notebook or not at all, and everything after the first conversation improvised in whatever system a team could reach for.
Our team built a platform that closes the loop. Lists of any layout are imported through a mapping wizard whose templates make the second import trivial, with unmapped columns promoted into tenant-defined fields rather than dropped. Agents work from a map on their phone, log each doorstep outcome against a configurable question set, and have the visit verified against the device's own position — with the property coordinates, device coordinates and computed distance retained as evidence rather than reduced to a flag. Leads that go somewhere are promoted through follow-up, nurture marketing, purchase and closed-deal stages, each with its own configurable field set and views, and each still traceable to the record it came from.
Around that sit the parts a multi-tenant platform needs to be a product rather than a project: a data model that is configuration instead of code, tenant provisioning from working defaults, appointments synchronised to a calendar and reinforced by SMS, marketing automation for the leads that are not ready yet, commission and activity reporting for the people who manage the work, and a dual audit trail — machine-readable for compliance, readable for everyone else. Delivered as a React Native field application over a multi-tenant Laravel API and web back office, it replaces a paper process with one that is faster at the door and answerable afterwards.