```html

Building a Self-Contained Tenant Portal with Zelle Payment Integration on dangerouscentaur.com

What Was Done

We built a complete, domain-isolated tenant management system for a property rental operation. The system includes a secure tenant hub portal with credential management, a receipt logging infrastructure for Zelle payments, and an automated email-to-payment pipeline that eliminates manual accounting overhead.

Key accomplishments:

  • Deployed a fresh tenant hub at https://3028fiftyfirststreet.92105.dangerouscentaur.com/ with generated credentials
  • Sent tenant credentials via SES using the dangerouscentaur.com domain (not queenofsandiego.com)
  • Built a Zelle payment forwarding system that auto-logs payments when emails are forwarded to a dedicated inbox
  • Completely isolated all infrastructure from the primary queenofsandiego.com domain

Technical Architecture

Frontend: Tenant Hub Portal

The tenant portal lives at /Users/cb/Documents/repos/sites/dangerouscentaur/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/index.html and serves as the single-page application (SPA) for tenant interactions. We modified it to:

  • Display freshly generated per-tenant credentials in a secure credentials table
  • Load receipt history from the S3-backed receipts.json file
  • Provide a dashboard section for viewing logged payments

The portal is deployed to an S3 bucket and served through CloudFront (distribution ID: dc-sites stack). We invalidated the cache after each deployment to ensure tenants see fresh data immediately:

aws cloudfront create-invalidation \
  --distribution-id [DIST_ID] \
  --paths "/index.html" "/scripts/*"

Backend: Lambda Functions

Two Lambda functions form the backend:

receipt-action Lambda (/scripts/lambda-receipt-action/lambda_function.py):
This function handles authenticated admin actions for payment logging. It validates incoming requests using an ADMIN_TOKEN environment variable and supports the log_rent_payment action. The function:

  • Accepts JSON payloads with action, tenant_id, amount, payment_method, and notes fields
  • Reads the current receipts.json from S3
  • Appends a new receipt entry with timestamp
  • Writes back to S3 with proper permissions
  • Returns success/failure responses

email-parser Lambda (/scripts/lambda-email-parser/lambda_function.py):
This function parses incoming emails forwarded to a dedicated inbox and extracts Zelle payment details. It:

  • Receives SES events from a configured rule
  • Extracts sender, subject, and body content
  • Uses regex patterns to identify Zelle transaction amounts and dates
  • Invokes the receipt-action Lambda to log the payment automatically

Email Infrastructure

We configured ImprovMX aliases on the dangerouscentaur.com domain to handle payment emails. The setup includes:

  • A payments@dangerouscentaur.com alias that forwards to your personal email
  • An SES rule that captures forwarded Zelle notifications and triggers the email-parser Lambda
  • DKIM/DMARC verification tokens configured in Route53 for domain authentication

Tenant credential emails are sent via SES with the sender address configured as a verified identity in the dangerouscentaur.com domain (not queenofsandiego.com, addressing the previous domain isolation issue).

Key Implementation Details

Credential Management

Fresh temporary passwords were generated using secure random methods and hashed for storage in the HTML credentials table. The index.html file was updated with:

  • Per-tenant login IDs and initial passwords
  • A user credentials section that tenants see upon first login
  • Instructions to change passwords immediately

Credentials were distributed via SES using the command:

aws ses send-email \
  --from payments@dangerouscentaur.com \
  --to [TENANT_EMAIL] \
  --subject "Your Tenant Portal Credentials" \
  --text "Your login ID: [ID]\nTemporary Password: [PASSWORD]\nPortal: https://3028fiftyfirststreet.92105.dangerouscentaur.com/"

Payment Logging Flow

The Zelle forwarding system works as follows:

  1. You receive a Zelle notification email from your bank
  2. You forward it to payments@dangerouscentaur.com
  3. ImprovMX receives it and also triggers an SES rule
  4. The SES rule invokes the email-parser Lambda
  5. The parser extracts amount and date, identifies the tenant from email context
  6. The parser calls receipt-action Lambda with log_rent_payment action
  7. receipt-action appends to receipts.json in S3
  8. The tenant hub dashboard auto-refreshes to show the new payment

Domain Isolation

All resources live within the dangerouscentaur.com domain. We explicitly avoided using queenofsandiego.com infrastructure:

  • DNS/Route53: All 3028fiftyfirststreet.92105.dangerouscentaur.com records point to CloudFront
  • SES: Verified sender identity is payments@dangerouscentaur.com, not queenofsandiego.com
  • S3 buckets: Deployed to dc-sites stack resources, not shared buckets
  • Lambda functions: Configured with environment variables and IAM roles specific to dangerouscentaur.com resources

Infrastructure Changes

The following AWS resources were created/modified:

  • S3: Receipt data stored at s3://[DC-SITES-BUCKET]/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/receipts.json
  • Lambda: Two functions deployed with Function URLs for direct HTTP invocation
  • CloudFront: Cache invalidation applied to distribution serving the tenant hub
  • SES: Domain verification initiated for dangerouscentaur.com; aliases configured via ImprovMX