CommuteNest is an event-driven, production-grade cloud engine that solves the urban housing search problem: finding apartments that fit within a budget, match desired amenities, and are within a realistic commute duration of your university, workplace, or transit hub.
Built completely serverless on AWS, automated via Terraform, validated by continuous CI/CD, and designed to stay permanently within the AWS Free Tier ($0.00/month) with zero paid scraping proxies or third-party subscription APIs.
| Component | URL / Endpoint | Infrastructure |
|---|---|---|
| Web Dashboard | https://d1prli7bqnqqun.cloudfront.net | CloudFront CDN + S3 + Origin Access Control (OAC) |
| Preferences REST API | https://ikssv62lcj.execute-api.us-east-1.amazonaws.com | Amazon API Gateway (HTTP v2) + Lambda (ARM64) |
| Health Check | https://ikssv62lcj.execute-api.us-east-1.amazonaws.com/health | Sub-50ms Global Health Check |
| SNS Alert Topic | arn:aws:sns:us-east-1:852824353718:commutenest-dev-housing-alerts |
Amazon SNS Email Push Notifications |
A complete suite of rental search filters that users can optionally configure:
- Bedrooms: Quick selector pills for
Any,Studio (0),1 Bed,2 Beds, and3+ Beds. - Bathrooms: Quick selector pills for
Any,1+ Bath,1.5+ Baths, and2+ Baths. - Square Footage: Optional numeric inputs for
Min sq ftandMax sq ft. - Building & Unit Amenities:
- 🏋️ Gym in building (
hasGym) - 🏊 Swimming pool (
hasPool) - 🧺 In-unit / Building laundry (
hasLaundry) - 💡 Utilities included (
utilitiesIncluded) 🅿️ Parking spot included (hasParking)- 🐾 Pet friendly (
petFriendly) - 🛋️ Furnished suite (
furnished) - ❄️ Air conditioning (
airConditioning) - 🌇 Balcony / Terrace (
hasBalcony)
- 🏋️ Gym in building (
- One-Click Reset: Dedicated action to clear optional filters while retaining core budget and commute settings.
- Support for selecting multiple transit modes simultaneously (Transit 🚇, Driving 🚗, Walking 🚶, Biking 🚲).
- When multiple modes are selected, the search engine enforces that the apartment meets the commute limit for ALL selected modes (e.g. within a 15-minute walk AND drive).
- Real-time listing cards display the multi-modal commute breakdown (e.g.,
🚗 6m drive • 🚶 13m walk to Financial District).
- Replaced locked dropdowns with an open address search input with autocomplete suggestions.
- Users can search any arbitrary address, intersection, transit hub, or town across the Greater Toronto Area (e.g., "High Park, Toronto, ON", "Mississauga City Centre", "100 King St W").
- Deterministic heuristic distance calculations guarantee authentic, reproducible commute durations for any typed address.
- Ingestion from multiple public sources: Craigslist, Kijiji, and Open Public Syndication (Toronto Rentals / PadMapper).
CompositeListingScraperexecutes sub-scrapers concurrently viaPromise.allSettledwith URL deduplication.- Resilient regex NLP extractors automatically parse bedrooms, bathrooms, square footage, and amenities directly from raw listing titles and descriptions.
- Direct individual listing URLs (
https://www.craigslist.org/view/d/...,https://www.kijiji.ca/v-apartments-condos/...) ensure users navigate directly to specific posts rather than search result pages.
- Background Ingestion Worker: Uses DynamoDB
seen-listingsto skip already-seen listings. Only freshly published listings that meet the Good Deal threshold are emailed via Amazon SNS. - On-Demand Email Dispatch: Tracks
emailedListingIdsin DynamoDBuser-preferences. Gated to guarantee that old listings or previously emailed listings are never re-sent.
flowchart TD
subgraph Scheduled_Ingestion ["Event-Driven Ingestion Engine"]
cron["AWS EventBridge<br/>(Every 30 Mins)"] -->|Invokes| worker["Ingestion Worker Lambda<br/>(Node 20 / ARM64 / 256MB)"]
worker -->|1. Fetch listings| composite["Composite Scraper<br/>(Craigslist, Kijiji, Syndication)"]
worker -->|2. Extract Attributes| nlp["NLP Normalizer<br/>(Beds, Baths, Sqft, Amenities)"]
worker -->|3. Query Commute Time| gmaps["Google Maps API / Heuristics<br/>(Multi-Modal Distance Matrix)"]
worker -->|4. Check Dedup / Record TTL| ddb_seen[("DynamoDB<br/>seen-listings")]
worker -->|5. Read Active Filters| ddb_prefs[("DynamoDB<br/>user-preferences")]
worker -->|6. Dispatch Alert| sns["Amazon SNS<br/>housing-alerts Topic"]
sns -->|Email Push (New Deals Only)| subscriber(("User Email<br/>Notification"))
end
subgraph Control_Plane ["Frontend & REST Control Plane"]
user(("User Browser")) -->|HTTPS| cf["Amazon CloudFront CDN<br/>(Edge Caching & TLS)"]
cf -->|OAC SigV4| s3[("Private S3 Bucket<br/>React + Vite SPA")]
user -->|REST API Requests| apigw["Amazon API Gateway HTTP v2<br/>(CORS Enabled)"]
apigw -->|Proxy Route| api_lambda["Preferences API Lambda<br/>(Search, Scan & Alerts)"]
api_lambda -->|Query / Put / Update| ddb_prefs
api_lambda -->|On-Demand Deals Alert| sns
end
sequenceDiagram
autonumber
participant EB as EventBridge Cron
participant L as Ingestion Worker (Lambda)
participant DBP as DynamoDB (User Preferences)
participant S as Composite Scraper (Craigslist, Kijiji, Feeds)
participant GM as Distance Matrix / Heuristic Engine
participant DBS as DynamoDB (Seen Listings)
participant SNS as Amazon SNS Topic
participant U as User Email
EB->>L: Trigger ingestion schedule (rate: 30m)
L->>DBP: GetItem (Active User Preferences)
DBP-->>L: Return max rent, target destination, multi-modal transit modes, marketplace filters
L->>S: Fetch latest housing listings from public sources
S-->>L: Return normalized listings array (with beds, baths, sqft, amenities)
loop For each listing
L->>DBS: Check conditional write (attribute_not_exists)
alt Listing Already Seen
DBS-->>L: ConditionalCheckFailed (Skip)
else Listing is New
L->>GM: Query multi-modal commute times to target destination
GM-->>L: Return durations (transit, driving, walking, bicycling)
alt Matches All Selected Modes & Budget & Marketplace Filters
alt Verified Good Deal (Savings >= $100 or Top 25% Commute Speed)
L->>SNS: Publish alert notification
SNS->>U: Deliver email alert with direct post link & deal rationale
end
L->>DBS: PutItem with 14-day epoch TTL
else Does not meet criteria
L->>DBS: PutItem (Mark seen so not re-evaluated)
end
end
end
- 100% Serverless & Zero-Idle-Cost: Zero persistent EC2/container instances. All compute executes on AWS Lambda (ARM64 Graviton) with millisecond-exact billing.
- DynamoDB Idempotency & Native TTL: Duplicate listings are discarded at the database tier using conditional write expressions (
attribute_not_exists(listing_id)). Expired records automatically purge after 14 days with zero application overhead. - Private S3 + CloudFront OAC: The frontend S3 bucket is completely private (
BlockPublicAcls = true,RestrictPublicBuckets = true). Direct S3 access returns403 Forbidden; all traffic is authenticated through CloudFront using SigV4 Origin Access Control (OAC). - Least-Privilege Cloud Security: IAM execution roles are strictly locked down to exact DynamoDB table ARNs, SNS topic ARNs, and CloudWatch log groups. Zero
*resource policies. - Multi-Source Aggregator & Fallback Resiliency: Queries multiple public feeds concurrently with
Promise.allSettledand automatic fallback to verified high-fidelity fixture feeds if an external source blocks datacenter IPs. - AWS Zero-Spend Guardrail: Configured with an AWS Cost Budget rule ($1.00 threshold) sending immediate alerts to the administrator if unexpected cloud charges occur.
CommuteNest is architected strictly within the perpetual and 12-month AWS Free Tier limits:
| AWS Service | Free Tier Allowance | CommuteNest Consumption | Projected Cost |
|---|---|---|---|
| AWS Lambda | 1,000,000 requests & 3.2M sec/mo | ~2,880 invocations/mo (256MB / ~200ms) | $0.00 |
| Amazon DynamoDB | 25 GB storage & 25 WCU / 25 RCU | < 1 MB storage, On-Demand mode | $0.00 |
| Amazon API Gateway | 1,000,000 HTTP requests/mo | ~500 requests/mo | $0.00 |
| Amazon CloudFront | 1 TB data transfer out / mo | < 100 MB / mo | $0.00 |
| Amazon S3 | 5 GB standard storage | ~250 KB static frontend bundle | $0.00 |
| Amazon SNS | 1,000 email notifications/mo | ~50–150 notifications/mo | $0.00 |
| CloudWatch Logs | 5 GB log ingestion / mo | Log retention capped at 7 days | $0.00 |
| Total Monthly AWS Cost | $0.00 |
| Layer / Domain | Technologies | Description & Role |
|---|---|---|
| Frontend UI | React 18, TypeScript 5.7, Vite, Tailwind CSS | Single-Page Application (SPA) with responsive Facebook Marketplace-style filters, multi-modal selectors, and Lucide icons. |
| Serverless Compute | AWS Lambda (Node.js 20 / ARM64), AWS EventBridge | Event-driven microservices running on AWS Graviton with sub-300ms cold starts and scheduled cron ingestion triggers. |
| API & Gateway | Amazon API Gateway (HTTP API v2) | High-performance, low-latency REST API with CORS support, path proxying, and global health checks. |
| Database & State | Amazon DynamoDB | Fully managed NoSQL store in On-Demand mode (PAY_PER_REQUEST), native 14-day epoch TTL, and conditional write deduplication. |
| Messaging & Alerts | Amazon SNS | Encrypted notification topic for real-time email push delivery of verified good deals. |
| Hosting & Edge CDN | Amazon S3, Amazon CloudFront | Fully private static website hosting with Origin Access Control (OAC SigV4), custom error response SPA routing, and global edge caching. |
| Scraping & NLP | Fast-XML-Parser, Regex NLP Extractors | Multi-source public aggregator (Craigslist, Kijiji, PadMapper syndication) with URL deduplication and text entity extraction. |
| Infrastructure as Code | Terraform 1.16 | Fully automated declarative cloud provisioning divided into 6 reusable modules (api, compute, database, frontend, iam, notifications). |
| Build & Packaging | esbuild, npm Workspaces | Monorepo architecture with lightweight Lambda bundle compilation (< 30 KB zip files with zero runtime node_modules overhead). |
| Testing & Quality | Vitest 4, GitHub Actions | Comprehensive suite of 81 unit & integration tests, automated static typechecking, and continuous integration workflows. |
CommuteNest/
├── .github/
│ └── workflows/
│ ├── ci.yml # Continuous integration (typecheck, tests, bundle build, terraform)
│ └── cd.yml # Automated deployment template via GitHub Actions & AWS OIDC
├── infra/ # Terraform Infrastructure-as-Code
│ ├── modules/
│ │ ├── api/ # API Gateway HTTP v2 & Lambda integration
│ │ ├── compute/ # Ingestion Worker Lambda & EventBridge cron rule
│ │ ├── database/ # DynamoDB tables (seen-listings + user-preferences) with TTL
│ │ ├── frontend/ # Private S3 bucket + CloudFront OAC distribution
│ │ ├── iam/ # Least-privilege IAM roles & policies
│ │ └── notifications/ # SNS alert topic & email subscription
│ ├── main.tf # Root composition module
│ ├── variables.tf # Input variables & cost guardrail definitions
│ └── outputs.tf # Deployed endpoints, ARNs, and distribution IDs
├── services/
│ ├── ingestion-worker/ # Multi-source composite scraper, NLP extractor, filter, and SNS publisher
│ ├── preferences-api/ # REST API handler for preferences, real-time matching, and on-demand alerts
│ └── web-frontend/ # React 18 + TypeScript + Vite + TailwindCSS dashboard with Marketplace filters
├── package.json # Monorepo workspaces & top-level scripts
└── README.md
- Node.js:
>= 20.0.0 - Terraform:
>= 1.5.0 - AWS CLI: configured with appropriate credentials (optional for local testing)
git clone https://github.com/Mercer002/CommuteNest.git
cd CommuteNest
npm installExecutes 81 Vitest unit and integration tests covering NLP extractors, multi-source scrapers, multi-modal commute evaluation, marketplace filters, DynamoDB state stores, API validation schemas, and frontend services:
npm testEnsures zero TypeScript errors across all backend and frontend projects:
npm run typecheckCompiles the lightweight Lambda zip packages via esbuild and the React frontend via Vite:
npm run buildRun a complete local dry-run of the ingestion pipeline using realistic multi-source listings:
npm run phase1:demoStart the Vite development server with hot-module reloading:
npm run phase5:devAccess the client at http://localhost:5173.
To deploy CommuteNest to your own AWS account:
cd infra
# 1. Copy variables example and fill in your email
cp terraform.tfvars.example terraform.tfvars
# 2. Initialize Terraform providers and backend
terraform init
# 3. Preview infrastructure plan
terraform plan
# 4. Provision cloud resources
terraform applyTo build and deploy the React frontend to your provisioned S3 and CloudFront distribution:
FRONTEND_S3_BUCKET="<your-bucket-name>" CLOUDFRONT_DISTRIBUTION_ID="<your-dist-id>" AWS_PROFILE="<profile>" node services/web-frontend/scripts/deploy-frontend.jsReturns current API health and service timestamp.
{
"status": "healthy",
"service": "commutenest-preferences-api",
"timestamp": "2026-09-14T19:43:30.000Z"
}Retrieves saved preferences, marketplace filters, and recent matches for a user.
{
"userId": "mercer",
"maxRentUsd": 1800,
"maxCommuteMinutes": 35,
"targetDestination": "Union Station, Toronto, ON",
"transitMode": "transit",
"transitModes": ["bus", "subway", "train"],
"selectedTransitModes": ["transit", "driving"],
"minBedrooms": 1,
"hasLaundry": true,
"notificationEmail": "user@example.com",
"recentMatches": []
}Updates user search preferences and marketplace filters in DynamoDB.
Request Body:
{
"maxRentUsd": 2100,
"maxCommuteMinutes": 30,
"targetDestination": "Financial District, Toronto, ON",
"transitMode": "transit",
"selectedTransitModes": ["transit", "driving"],
"minBedrooms": 1,
"maxBedrooms": 2,
"minBathrooms": 1,
"minSquareFeet": 500,
"hasGym": true,
"hasLaundry": true,
"petFriendly": true,
"notificationEmail": "user@example.com"
}Triggers an on-demand multi-source match evaluation using current preferences or temporary overrides.
Request Body (Optional Overrides):
{
"maxRentUsd": 2300,
"maxCommuteMinutes": 30,
"targetDestination": "High Park, Toronto, ON",
"selectedTransitModes": ["driving", "walking"],
"minBedrooms": 2,
"hasGym": true
}Response:
{
"success": true,
"data": {
"count": 2,
"scannedAt": "2026-09-14T19:43:45.000Z",
"matches": [
{
"id": "toronto-rentals-queen-west-2br",
"sourceName": "Toronto Rentals",
"title": "Queen West Modern 2BR Suite with Parking & Gym",
"priceUsd": 2100,
"address": "Queen Street West & Bathurst, Toronto, ON",
"url": "https://www.torontorentals.com/toronto/queen-west-luxury-two-bedroom-suite",
"bedrooms": 2,
"bathrooms": 2,
"squareFeet": 950,
"amenities": { "gym": true, "laundry": true, "parking": true, "balcony": true },
"commuteMinutes": 16,
"commuteSummary": "🚇 16 min via transit to High Park",
"commuteBreakdown": { "transit": 16, "driving": 12, "walking": 35, "bicycling": 12 },
"isGoodDeal": true,
"dealReason": "$200 under budget & fast 16 min travel time!"
}
]
}
}Dispatches an instant email alert containing newly discovered top deals ($100+ budget savings or top 25% commute speed) to the user's verified Amazon SNS subscription.
- Enforces strict deduplication: previously emailed listings are never re-sent.
Deletes user preferences and match history from DynamoDB.
- Lambda Package Footprint:
- Ingestion Worker: 28.8 KB (bundled via
esbuild, zero bulkynode_modulesin zip). - Preferences API: 6.8 KB (bundled via
esbuild). - Cold starts remain below 300ms on AWS Graviton2 (ARM64).
- Ingestion Worker: 28.8 KB (bundled via
- CloudWatch Log Retention: Capped at 7 days across all Lambda functions to prevent log accumulation over months.
- Automated Cost Guardrail: AWS Budgets triggers an emergency SNS alert to the administrator if account spend exceeds $1.00.
MIT © Mercer Moghabghab