Skip to main content

Architecture overview

Launchpad V2 is a normalized-ingestion + governed-reporting platform with separate paid-media, commerce, attribution, configuration, and delivery planes.

Subsystems​

Core planes​

1. Ingestion (Inngest)​

  • Shared durable functions execute connector-specific fetch stages and write to the connector's analytics/configuration paths.
  • Paid facts use deterministic event identity plus the ClickHouse ordered grain/version contract. Connector-specific ledgers have their own identity rules.
  • Concurrency is function-specific: some paths serialize globally while others key by binding or client. Read each Inngest function's configuration before changing it.

2. Analytics, commerce, and attribution (ClickHouse)​

  • User-facing tenant reads resolve server-side scope before querying. Background, audit, and internal paths must carry an explicit verified tenant scope appropriate to their caller.
  • Uses the relevant maintained latest-state view or ledger path; mv_ad_daily_rollup is only one paid-acquisition surface.
  • Hierarchy queries follow the 6-level order (see Data model).

3. Configuration and credentials (Supabase)​

  • Owns tenants, users/RBAC, brands, bindings, report settings, and secret pointers.
  • Uses RLS plus server-side scope resolution; ClickHouse client_id maps to the client slug.

4. Creative QC and operator workflows​

  • Registry of checks: caption, qc_score, field_presence, compliance_v1, lander_congruency.
  • One durable Inngest fn + per-check plug-in files.
  • Writes to creative_check_results in ClickHouse; ad_check_status upsert in Supabase drives the Review Queue.

Hard rules​

These are the "if you break this, everything downstream breaks" rules. Use the available tests and audits for the path you change; not every rule has a universal automated guard.

  1. Every user-facing marketing entrypoint resolves server-side scope. Background/audit callers must supply and test an explicit tenant boundary. Cross-client leakage is a security incident.
  2. Rollups are derived, never written. mv_ad_daily_rollup is a plain VIEW computed at read time. Never write to a rollup, and never re-introduce an accumulating materialized view over a ReplacingMergeTree source — that bug inflated production spend 8× once.
  3. event_id is deterministic. Don't include timestamps or nonces in the hash inputs.
  4. Hierarchy is 6 levels in fixed order. UI code that special-cases level order will drift and eventually leak.
  5. Source definitions stay explicit. Ad account/source is one reporting dimension, while platform, CRM, attribution, and commerce metrics retain their own provenance and denominators.

Key files by concept​

ConceptFileNotes
Tenant scopingsrc/lib/auth-scope.tsresolveQueryScope() — the fail-closed chokepoint
RBACsrc/lib/rbac.tsRoles, permissions, grants. Single source of truth
Nav gatingsrc/lib/nav.tsPermission-driven menu, derived from rbac.ts
ClickHouse queriessrc/lib/marketing/queries.ts, src/lib/health-queries.tsEvery tenant query carries a client_id filter
Ad-platform fetcherssrc/lib/marketing/platform-fetch.ts, src/lib/marketing/platforms/See that folder's guide (AGENTS.md)
Check runnersrc/inngest/creative-check.tsThe one QC runner, driven by src/lib/checks/registry.ts
Background jobssrc/inngest/Registry is the functions array in functions.ts
Auth gatesrc/proxy.tsNext.js 16's renamed middleware.ts, Node runtime. Layout guards remain the primary gate
Validated env accesssrc/lib/env.tsPrimary Zod schema; direct runtime/build reads also exist and must be inventoried
Fact table naming

The ClickHouse paid fact table is marketing_paid_acquisition (a ReplacingMergeTree). mv_ad_daily_rollup is a plain view over the maintained latest-state path and stores nothing. See ClickHouse rollups.

Continue to Data model for the schema-level view.