Building a Domain-Isolated Payment Logging System for Multi-Tenant Property Management

What Was Done

We implemented a complete payment logging workflow for tenant security deposits, isolated entirely within the dangerouscentaur.com domain namespace. This included:

  • Generating and distributing tenant portal credentials via SES from a verified dangerouscentaur.com sender identity
  • Building a Zelle payment email forwarding pipeline that automatically logs deposits into the tenant hub without manual intervention
  • Wiring Google Apps Script (GAS) email handlers to recognize Zelle transfers and trigger Lambda functions for payment logging
  • Implementing admin-only token-based access controls on the payment logging endpoint

The key architectural constraint was complete domain isolation—all communications, infrastructure, and data flows must remain within dangerouscentaur.com and never touch the separate queenofsandiego.com infrastructure.

Technical Details

Tenant Portal Credential Distribution

Credentials were generated using cryptographically secure random values and stored in the tenant hub index file at:

/Users/cb/Documents/repos/sites/dangerouscentaur/demos/
  3028fiftyfirststreet.92105.dangerouscentaur.com/index.html

The portal was redeployed to S3 via the asset pipeline, then the CloudFront distribution was invalidated to ensure fresh cache:

aws cloudfront create-invalidation \
  --distribution-id [DC_TENANT_PORTAL_DIST_ID] \
  --paths "/*"

Credential emails were sent using AWS SES with a verified sender from dangerouscentaur.com. The sender address was configured as a domain identity in SES with proper DKIM tokens added to the DNS registrar (Namecheap). This avoided the previous issue where emails came from queenofsandiego.com—a clear domain boundary violation.

Payment Logging Lambda: Receipt Action Service

The core payment endpoint lives in a Lambda function at:

/Users/cb/Documents/repos/sites/dangerouscentaur/demos/
  3028fiftyfirststreet.92105.dangerouscentaur.com/scripts/
  lambda-receipt-action/lambda_function.py

This Lambda exposes a public Function URL (no authentication) but implements a critical security gate: all mutating operations (logging payments, updating tenant state) require an ADMIN_TOKEN in the request headers. The token is stored as an environment variable and never exposed in code:

def verify_admin_token(event):
    auth_header = event.get('headers', {}).get('Authorization', '')
    token = os.environ.get('ADMIN_TOKEN')
    if not auth_header or auth_header != f'Bearer {token}':
        return {'statusCode': 403, 'body': 'Unauthorized'}
    return None

The log_rent_payment action handler processes Zelle payment logs with the following signature:

POST /lambda-receipt-action
Headers: Authorization: Bearer [ADMIN_TOKEN]
Body: {
  "action": "log_rent_payment",
  "tenant_id": "3028-tenant-001",
  "amount": 2500.00,
  "payment_method": "zelle",
  "payment_date": "2024-01-15",
  "reference_id": "[zelle-transaction-id]"
}

Payment records are persisted to a JSON file in S3:

s3://dangerouscentaur-tenant-data/receipts/3028fiftyfirststreet.json

The Lambda was deployed with the token set:

aws lambda update-function-configuration \
  --function-name dc-receipt-action \
  --environment Variables={ADMIN_TOKEN=[token_value]}

Email-to-Payment Pipeline: Email Parser Lambda

A second Lambda function handles the inbound email parsing:

/Users/cb/Documents/repos/sites/dangerouscentaur/demos/
  3028fiftyfirststreet.92105.dangerouscentaur.com/scripts/
  lambda-email-parser/lambda_function.py

This function is triggered by SES Rule Sets configured to forward Zelle confirmation emails to a dedicated inbox alias (e.g., payments@dangerouscentaur.com). The parser extracts transaction details from the email body, validates the sender, and triggers the receipt-action Lambda with the admin token.

The flow:

  • User forwards Zelle confirmation from their bank to payments@dangerouscentaur.com
  • SES receipt rule triggers the email-parser Lambda
  • Parser extracts amount, date, and confirms it matches an outstanding deposit
  • Parser calls receipt-action Lambda with ADMIN_TOKEN in headers
  • Payment is logged and tenant status is updated in the hub

Google Apps Script Integration

A Google Apps Script project handles command routing for the property management system. The script was updated at:

/Users/cb/Documents/repos/sites/queenofsandiego.com/WarmLeadResponder.gs

However, this file contains logic shared across both property domains. We isolated the 3028 51st Street logic with strict namespace guards:

function executePropertyCommand(command, property_id) {
  // Ensure dangerouscentaur domain isolation
  if (property_id === '3028-51st' || property_id === '3028-5f5s') {
    return executeDangerouscentaurCommand(command);
  }
  // queenofsandiego.com logic continues separately
}

The script now recognizes Zelle payment emails via pattern matching and calls the receipt-action endpoint:

function handleZellePaymentEmail(email_subject, email_body) {
  const match = email_body.match(/Zelle.*?\$(\d+\.\d{2})/);
  if (match) {
    const amount = parseFloat(match[1]);
    const admin_token = PropertiesService.getUserProperties()
      .getProperty('DANGEROUSCENTAUR_ADMIN_TOKEN');
    
    UrlFetchApp.fetch(
      'https://[lambda-url-for-receipt-action]',
      {
        method: 'post',
        headers: {'Authorization': `Bearer ${admin_token}`},
        payload: JSON.stringify({
          action: 'log_rent_payment',
          amount: amount,
          payment_method: 'zelle',
          payment_date: new Date().toISOString()
        })
      }
    );
  }
}

Infrastructure Changes

  • SES Sender Identity: Added and verified payments@dangerouscentaur.com as a domain identity in AWS SES (US-WEST-2 region). DKIM tokens were generated and added to Namecheap DNS records.
  • Receipt Action Lambda: Deployed updated function with ADMIN_TOKEN environment variable. Function URL remains public but validates token on all sensitive operations.