Identity and RBAC
Firebase ID tokens, Google Workspace sign-in, server-side role checks, and separate browser/server package entry points kept auth reusable without leaking runtime dependencies.
Several internal business applications needed the same identity, UI, customer, audit, and utility patterns. Instead of copying those decisions app by app, I built a shared platform layer so each product could focus on its business workflow while inheriting a consistent security, frontend, and integration baseline.
// Before and after
App-specific login and role checks
Repeated frontend shell and API error handling
Customer values embedded in individual apps
One-off FX-rate handling
Inconsistent audit trails
Manual or app-specific deployment patterns
Shared Firebase and Google Workspace auth package plus auth service
Shared app shell, UI components, API utilities, and frontend guide
Customer master service with typed package and React hooks
Bank of Canada FX service with cache, fallback, scheduler, and client package
Audit service with app-scoped queries and service-to-service writes
OpenTofu modules and WIF-based CI/CD
// Architecture
The architecture split each reusable capability into two halves: a Cloud Run service that owns the API and data model, and a typed package that gives consumer apps a stable client, hook, middleware, or component contract.
Firebase ID tokens, Google Workspace sign-in, server-side role checks, and separate browser/server package entry points kept auth reusable without leaking runtime dependencies.
A shared shell, sidebar, table, status, modal, theme, API fetch, and response-parsing layer gave every app the same baseline interaction model.
A Bank of Canada FX-rate service cached daily rates, handled prior-business-day fallback, and exposed typed hooks for app usage.
A customer master service consolidated customer records, duplicate detection, soft delete, event publishing, and React consumption.
A centralized audit service used OIDC writes, app-scoped query access, validation, and cursor pagination for consistent operational history.
OpenTofu modules, per-service IAM, Cloud Run, Artifact Registry, private npm publishing, and path-filtered deploys turned platform work into a repeatable delivery system.
// Design choices
The work was not just standing up services. It was deciding where boundaries should sit, which contracts deserved packages, which data should be shared, and which security controls needed to be standard instead of optional.
Separate package entry points for browser and server runtimes.
Optional peer dependencies so apps install only what their runtime needs.
Service-specific GCP service accounts with least-privilege IAM.
Firebase token auth for user-facing APIs and OIDC auth for internal service calls.
Global reference data exception for FX rates, documented separately from app-scoped data.
Private package registry because these were internal platform contracts.
// The takeaway
I recognized a product-line architecture opportunity inside a set of internal tools and turned repeated delivery decisions into reusable services, packages, and standards. That is the kind of architecture work that compounds: each new app starts from a stronger baseline than the last one.