ADR-010: Tenant Engine Architecture

Status: Accepted Owner: @bilal @deen Date: 2025-01-10

Context

Envo’s core value proposition is 24/7 automated tenant support. The Tenant Engine enables tenants to report issues and receive responses through multiple channels without requiring landlord intervention.

Channels: WhatsApp (primary V1, via Twilio), Voice AI (V1, via VAPI), Email (future), Web Chat (see ADR-016 Tenant Chat App).

Decision

1. Conversation Model

CREATE TABLE conversations (
    id UUID PRIMARY KEY,
    organisation_id UUID NOT NULL,
    tenant_id UUID REFERENCES tenants(id),
    property_id UUID REFERENCES properties(id),
    channel conversation_channel NOT NULL,  -- whatsapp, voice, email, chat, sms
    external_id TEXT,                       -- Twilio SID, VAPI call ID
    contact_phone TEXT, contact_email TEXT,  -- For unidentified tenants
    status conversation_status NOT NULL DEFAULT 'active',
    issue_id UUID REFERENCES issues(id),
    resolution_type resolution_type,
    started_at TIMESTAMPTZ, ended_at TIMESTAMPTZ,
    handled_by_ai BOOLEAN DEFAULT true,
    escalated_to_human BOOLEAN DEFAULT false,
    summary TEXT,
    metadata JSONB DEFAULT '{}'
);

2. Message Model

CREATE TABLE messages (
    id UUID PRIMARY KEY,
    conversation_id UUID NOT NULL REFERENCES conversations(id),
    direction message_direction NOT NULL,   -- inbound, outbound
    role message_role NOT NULL,             -- tenant, ai, staff
    content_type message_content_type NOT NULL,
    content TEXT,
    media_url TEXT, media_mime_type TEXT,
    audio_url TEXT,                          -- Compliance tier only
    transcript TEXT,                         -- Always stored for voice
    external_id TEXT,
    sent_at TIMESTAMPTZ, delivered_at TIMESTAMPTZ, read_at TIMESTAMPTZ
);

3. Conversation Flow

Tenant sends message/makes call
  → Webhook to Envo Engine
  → Create/update conversation + store message
  → AI processes message → response + intent
  → If issue detected: create issue, link to conversation, notify landlord
  → Store AI response, send to tenant

4. Tenant Identification

  1. Lookup by phone/email → match to existing tenant
  2. Lookup by property → check if phone matches property
  3. Unknown contact → store conversation with contact info, allow manual linking

5. What’s Stored by Default

Data TypeDefaultOptional
Chat messagesStored
Voice transcriptsStored
AI summariesStored
Media attachmentsStored
Call recordingsNot storedCompliance tier opt-in

6. AI Summaries

Generated when conversation ends, becomes inactive 24h, or manually closed. Captures: what tenant reported, AI response, outcome, key details.

7. Issue Auto-Creation

AI creates issues when: maintenance problem reported, emergency keywords detected, explicit help request. Includes auto-categorisation, urgency assessment, conversation link.

8. Storage Scaling

~150,000 messages/year at target scale (3,000 properties). PostgreSQL handles this easily. Design supports future partitioning or archive if needed.

Consequences

Positive

  • Complete audit trail of all tenant communications
  • Enables regulatory compliance
  • Rich reporting capability
  • Media capture works natively

Negative

  • Increased storage costs for media
  • More complex data model
  • Must handle failed message delivery