Back to work
AIInternal tool · NDA

Team Hub

Lifting the same agency's team operations app off a vendor platform and onto their own cloud, without downtime.

Role
Developer, migration lead on the application
Stack
TypeScript · React · Postgres · Pulumi · Cloud Run · Firebase Auth · Docker
Year
2026

Internal tool for the same ad agency. Live in staging, production in progress. No public link; screenshots are shared with permission, with some details redacted.

Context

Team Hub is the same agency's people-side application, running their meeting cadence, team assessments, training and onboarding. It is the sibling to Command Hub, which handles clients.

The problem was not the app. It was where it lived. The whole thing ran on a vendor AI platform: their login, their AI, their file storage, their database. The agency owned the product and none of the ground under it. My job was to move all of it onto the agency's own Google Cloud, without the team losing a day's use of it.

What I built

A migration in phases, each one shippable on its own rather than a milestone on a chart. Nothing moved until the phase before it was actually working.

  • Repositories moved off the vendor's GitHub and onto the agency's own.
  • A security pass, run before the migration rather than after: the audit found paths where employees could read each other's performance reviews, one-to-one notes and quiz answers. Those were closed first.
  • Every call home to the vendor platform removed from the codebase.
  • The database converted from MySQL to PostgreSQL: 63 tables at conversion, 65 now.
  • Vendor sign-in replaced with the agency's own Google authentication.
  • AI, file storage, email and notifications reconnected to Google equivalents. Transactional email went out and was confirmed delivered end to end, not assumed.
  • Deployed to Cloud Run, seeded with the real staff roster, and handed to the team for review.

Architecture

Application
TypeScript and React, on PostgreSQL.
Infrastructure
Pulumi, in a separate infrastructure repository from the application. Infrastructure is created by committing code, never by clicking in a console.
Deploys
Tag-triggered. A file, a branch, a pull request and even a merge are all inert: nothing reaches the cloud until a tag is pushed. Release-candidate tags go to staging, release tags to production.
Review gate
The infrastructure preview cannot be run locally, because it needs write access to the state bucket that a developer account does not have. So the pull request is the gate: CI runs the preview as the identity that will actually apply the change. The constraint produced a better process than the convenient version would have.
Auth
Google sign-in with a domain lock, moving to central identity and Firebase tenants in the current phase.

How AI was used to build it

This is the case study's real subject. Command Hub proved the process could work once; Team Hub is where it became repeatable.

The process itself is version-controlled. There is a separate repository holding only the project's intelligence: a CLAUDE.md, a kickoff prompt, architecture and platform context documents, month-by-month implementation logs, and dated action items from each of the team's sprint reviews. Every commit in it is a documentation commit. The code lives elsewhere; this repo is the memory that drives the work.

The commit subjects in that repo are the giveaway. They read as findings, not as tasks: six rows marked done did not actually work, and how they were found. The knowledge base asserted a policy that did not exist. A release tag on an unbuilt commit deploys nothing. Production blocked by a stale state lock from a build that died mid-apply. Writing those down is what stops the same afternoon being lost twice.

The most reusable artefact is a migration playbook I wrote deliberately app-agnostic, so it applies to the next app off the vendor platform rather than only this one. Its most valuable section is the reconnaissance phase, which lists the classes of trap that turned up empirically and would not appear in any inventory: undocumented second login paths, procedures with no permission guard, database breakage that only appears at runtime and type-checking cannot see, vendor coupling hiding outside the obvious module, and features that are ninety-five per cent built but unreachable.

Both applications had an undocumented second login path. Neither appeared in any inventory. That is exactly the kind of thing a playbook exists to catch, and the reason the second migration was calmer than the first.

Outcome and current status

Live in staging since August 2026, with the full deploy path proven end to end: image build, migration, permissions, release. The team reviews on staging. Transactional email went live and was confirmed delivering in late August.

Production is the next step, and the work has since expanded: the app is moving onto the agency's central platform services (shared identity, a gateway, a split front and back end, and a permissions API this app exposes for their central console).

Screenshots

Employee names and internal content are redacted. Layout and behaviour are unchanged.