Private repo case study

Turning repeated app needs into a shared services platform.

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.

Shared authFrontend standardsCustomer masterFX-rate serviceAudit trailOpenTofuArtifact RegistryWorkload Identity FederationCloud RunFirestoreShared authFrontend standardsCustomer masterFX-rate serviceAudit trailOpenTofuArtifact RegistryWorkload Identity FederationCloud RunFirestore

// Before and after

Repeated app work

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 platform layer

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

Services own the platform logic. Packages make it usable.

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.

Business apps

Billing and collections
Sales workflow
Future internal apps

Packages

auth package
ui package
customers package
fx package
audit package

Services

auth-service
customer-service
fx-service
audit-service

Data and integration

Firestore
Pub/Sub
Cloud Scheduler
Bank of Canada API
// Implementation highlights

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.

Frontend standards

A shared shell, sidebar, table, status, modal, theme, API fetch, and response-parsing layer gave every app the same baseline interaction model.

Business utilities

A Bank of Canada FX-rate service cached daily rates, handled prior-business-day fallback, and exposed typed hooks for app usage.

Shared business data

A customer master service consolidated customer records, duplicate detection, soft delete, event publishing, and React consumption.

Auditability

A centralized audit service used OIDC writes, app-scoped query access, validation, and cursor pagination for consistent operational history.

Delivery platform

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 useful signal is architecture judgment.

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.