Professional Experience

Telus Tenant Portal — Internal Smart Home Support Platform (Web)

Telus Tenant Portal — Internal Smart Home Support Platform (Web)
  • React
  • TypeScript
  • Material UI
  • TanStack Query
  • Kotlin
  • Java
  • Spring Boot
  • AWS Lambda
  • DynamoDB
  • OpenSearch
  • Docker
  • Terraform

Description

Tenant Portal is the internal system TELUS support operations run on — not the app customers use, but the tool support agents, technical specialists, and operations teams use to diagnose and manage the SmartHome+ device ecosystem on a customer's behalf. It's in daily use by distributed teams in Canada, Central America, and India, sitting in front of millions of connected IoT devices.

As Senior Software Engineer (Telus International, August 2022 – Present), I architected and delivered this platform end to end — React/TypeScript on the frontend, Kotlin/Java/Spring Boot and Node.js/Express services on the backend, running on AWS — and I'm the one who owns the tradeoffs behind it: what to make event-driven versus synchronous, how much to invest in observability before it pays off, and where clean architecture actually earns its cost versus where it's just ceremony. Requirements came from stakeholders, engineers, and QA across multiple regions, which meant designing for agents whose workflows, network conditions, and support volume differ by market, not for one reference user.

SmartHome+ is a paid subscription product wrapped around physical devices in someone's home — locks, cameras, sensors — so a bad support experience isn't just an inconvenience, it's a churn risk on recurring revenue and, in the case of security devices, a trust problem. Tenant Portal is also the piece of infrastructure that lets TELUS staff a follow-the-sun support model across Canada, Central America, and India at a shared cost base instead of each region running its own tooling — so the platform's economics matter as much as its feature set.

Impact at a Glance

  • ~40% improvement in application performance, at 99.9%+ availability — directly shortens how long an agent sits on a case, which is the main lever on cost-per-support-interaction at this scale
  • ~50% reduction in incident response and resolution time after investing in observability — fewer escalations and less customer-facing downtime to account for against SLAs
  • ~40% improvement in environment consistency and deployment reliability after moving to Infrastructure as Code — faster, safer releases mean new device integrations and features reach agents (and indirectly, customers) sooner
  • 85%+ automated test coverage across unit, component, and end-to-end layers — fewer regressions reaching a system agents depend on to do their job in real time
  • ~60% engineering productivity gain from deliberately structured AI-assisted workflows — more roadmap delivered without growing headcount

What It Gives an Agent

A support call starts with almost no context beyond a customer's account. The portal exists to close that gap fast:

  • Pull up a household and every device tied to it in one view
  • Read a device's current connection status and health, not just whether it's "online"
  • Trigger remote actions against a device directly from the case
  • Trace a diagnosis across an entire household instead of one device at a time
  • Look up customer profiles and manage subscriptions from the same screen
  • Search across the household base quickly enough to use mid-call
  • See data pulled from several backend services rendered as one coherent record, instead of an agent stitching it together from multiple internal tools

Every one of these is really about call-handle time: the less time an agent spends hunting for context across tools, the more cases a support team can close per shift without adding headcount.

Automation Visibility: Human and AI-Generated Routines

Devices in this ecosystem run on automation rules — some authored directly by the customer or an agent, others generated by an AI layer inferring useful automations from device behavior. Agents needed a way to see which rules were actually driving a device before troubleshooting it, so the portal surfaces both kinds of routines side by side against the same device timeline. That distinction matters operationally: a device "acting up" is a very different conversation when the cause is a human-configured rule versus an automated one nobody in the household consciously set — get that wrong on a call and the agent either escalates a case that didn't need it, or reassures a customer whose automation genuinely is misbehaving. Both outcomes cost the business: one in agent time, the other in repeat contacts and eroded trust.

Incident and Activity Visibility

Support is retrospective as often as it's live — an agent needs to reconstruct what happened on a device before the customer ever called. The portal's incident/log view gives agents that timeline directly, instead of requiring a separate ticket into another team to pull raw logs — turning what used to be a multi-day, cross-team investigation into something resolved on the first call, which is the difference between a satisfied customer and one who calls back.

Frontend Engineering

The UI is built as a component-driven React/TypeScript system, combining Material UI's component primitives with a shared data-table architecture — search, pagination, configurable columns, row selection, and per-row actions driven by shared context and reducers rather than re-implemented per screen. Server state (households, devices) is managed through TanStack Query rather than hand-rolled fetch-and-cache logic, which removed an entire category of stale-data and race-condition bugs that used to show up as "the table says something different than the device detail page." Domain data is exposed to components through typed custom hooks, keeping components themselves focused on presentation rather than data-fetching concerns.

Backend & Event-Driven Architecture

Core services are REST APIs in Kotlin, Java, and Spring Boot, with some services in Node.js/Express — deliberately not a single-language backend, since different services had different reasons to exist (some tied closely to existing Java domain logic, others needed to move fast on thinner, IO-bound endpoints). Layered onto that is a distributed, event-driven architecture using AWS Lambda, API Gateway, SQS, SNS, EventBridge, DynamoDB, and OpenSearch — necessary because polling millions of IoT devices synchronously doesn't scale, and a support agent needs near-real-time device state without the backend blocking on every device round-trip. That tradeoff isn't free: event-driven systems push complexity into idempotency, retry handling, and eventual consistency, so a meaningful part of the architecture work was making sure "eventually consistent" didn't leak into agent-facing screens as "occasionally wrong."

Object-oriented principles, SOLID design, and clean architecture boundaries in the Kotlin/Java services weren't applied as a checkbox — they're what kept a backend touched by a distributed team, over years, from calcifying into something only its original author could safely change. Security was treated as a design constraint from the start: input validation, authentication, authorization, and API design decisions were made with the assumption that this system holds access to real customers' home devices, not a low-stakes internal tool.

Testing & Reliability

Jest and React Testing Library cover frontend unit and component behavior, MSW mocks network boundaries so tests don't depend on live services, Vitest covers newer modules, and Cypress covers end-to-end flows that actually matter to an agent mid-call. The 85%+ coverage number is a byproduct of testing the right layers, not a target chased for its own sake — coverage on the reducer/state logic driving the shared tables mattered far more than coverage on presentational components.

Observability & Incident Response

CloudWatch metrics and alarms, real-user monitoring, dashboards, and Opsgenie paging turned "a device seems broken" from a multi-team investigation into something traceable from a single alert. Cutting incident response and resolution time by roughly half wasn't the result of one tool — it came from deciding upfront what needed to be observable (which service boundaries, which failure modes) instead of instrumenting reactively after an incident exposed a blind spot. In business terms, that's the gap between an outage that stays invisible to a handful of engineers and one that turns into a spike in support call volume across every region at once.

Infrastructure & Delivery

Deployment workflows run on Docker and Kubernetes, with GitLab CI/CD automating testing, validation, and production releases. Infrastructure as Code, via AWS CDK and Terraform, replaced manually provisioned environments — the ~40% gain in deployment reliability came specifically from eliminating environment drift between staging and production, which used to be a recurring source of "it worked in staging" incidents. The business case for this is time-to-market: every new device model or support feature TELUS wants agents equipped to handle ships faster when releases aren't gated on hand-configured environments.

AI-Assisted Engineering, Used Deliberately

GitHub Copilot, Amazon Q, Claude Code, and Cursor are part of the daily workflow — for code review, documentation, codebase analysis, and generating first-draft technical solutions. The ~60% productivity gain came from being specific about where AI helps: it's fast at producing a first pass and surfacing patterns across a large codebase, and it's not a substitute for deciding whether an event-driven approach is worth its complexity, or whether a "passing" migration actually preserved behavior. Alongside day-to-day use, I've run structured experiments with LLM APIs and prompting techniques aimed at developer workflows specifically — automated knowledge retrieval over internal documentation and codebases, and evaluating where AI-assisted capabilities are actually production-ready versus still a demo. For the business, that productivity gain is roadmap throughput: the same engineering team shipping more of what support operations and product are asking for, without headcount scaling linearly with device volume.

From Mocks to Real APIs

The frontend started against a json-server mock backend so UI work could move ahead of the real services. As those services matured, the app was migrated onto the real APIs — a deliberate cutover, not an incidental swap, since that's exactly where contract mismatches between mock and reality tend to surface.

Key Learnings

Event-driven architecture is a tradeoff, not a strict upgrade. Lambda, SQS, SNS, and EventBridge made it possible to handle device-scale traffic without the backend becoming a bottleneck, but every one of those queues and streams is a place where "eventually consistent" can become "occasionally wrong" if you don't deliberately design for it on the agent-facing side.

Observability is worth building before the incident that would have justified it. The ~50% cut in incident resolution time came from deciding in advance what needed to be measurable, not from adding dashboards after a bad outage exposed the gap.

AI tools are a force multiplier on throughput, not on judgment. Copilot, Amazon Q, Claude Code, and Cursor meaningfully sped up review, documentation, and first drafts — but the calls about event-driven complexity, clean-architecture boundaries, and IaC tradeoffs were still mine to make and defend.