Skip to main content

Architecture

High-Level

  • Frontend: Next.js/React app in frontend/
    • Uses App Router
    • Auth via Firebase client SDK; requests go through a centralized Axios apiClient (frontend/lib/api-client.ts) which injects Authorization (Firebase ID token) and x-organization-id headers.
  • Backend: Node.js + Express (TypeScript) in backend/
    • Mounted route prefixes like app.use('/api/google-ads', googleAdsRoutes) in backend/src/index.ts
    • Multi-tenant via tenantMiddleware that expects x-organization-id
    • Controllers in backend/src/controllers/*, services in backend/src/services/*
  • Database: PostgreSQL (Cloud SQL in production) accessed via helpers in backend/src/lib/database
  • Hosting/Infra: Cloud Run for backend. Frontend uses a public host (set NEXT_PUBLIC_API_URL to backend URL)
  • Analytics: Google Analytics 4 (GA4) integration

Key Integrations

  • Google Ads: OAuth flow, account listing, connection, campaigns
  • Meta Ads, TikTok Ads: Similar OAuth/connect flows
  • GA4: Property connection and server routes

Data Flow (Example: Google Ads Account Listing)

  1. User completes OAuth and lands on frontend/app/oauth/google-ads/success/page.tsx
  2. Page decodes tokens from query, shows GoogleAdsAccountSelector
  3. Selector calls GET /api/google-ads/auth/available-accounts?accessToken=...
  4. Backend controller (googleAdsController.getAvailableAccounts) → service (googleAdsService.getAvailableGoogleAdsAccounts)
  5. Service calls Google Ads API customers:listAccessibleCustomers and returns accounts (or actionable fallbacks)