Planning corpus: this is the real design-discussion doc for epic analytics-insights-and-import-adapters, synced verbatim from this repo’s own internal planning process.
Design Discussion: analytics-insights-and-import-adapters
0. Context
Backlog epic 46. User’s explicit ask: tie internal + external analytics together with real insights, both GA4 and PostHog, plus a pluggable import-adapter pattern.
Confirmed by direct inspection before any design work here: @mercatus-liber/analytics’s
AnalyticsAdapter (the PostHog wrapper) is write-only — track/identify/page, no read
method anywhere. @mercatus-liber/internal-bi’s BiMetricsAdapter is a real, owned read-side
(getRevenueOverTime/getOrderVolume/getTopProducts/getConversionFunnel/
getPromotionRedemptionRates) computed purely from this app’s own persistence — it has zero
notion of page views, traffic sources, or referrers, because that data is only ever sent
out via track()/page(), never stored internally. Neither existing package can answer “where
are visitors coming from” — that data genuinely only exists inside GA4/PostHog’s own systems
today, which is exactly the gap this epic closes.
1. Design questions
(a) A new contract, or extend BiMetricsAdapter?
Resolved: a new, separate contract, AnalyticsInsightsAdapter (packages/analytics, sibling
to the existing write-side AnalyticsAdapter in the same package — they’re related concerns,
read vs. write side of the same “analytics” subsystem, not different subsystems). Extending
BiMetricsAdapter would be wrong: that contract’s whole design premise (subsystem
20’s own design-discussion) is “computed purely from this app’s own persistence” — traffic/
referrer data doesn’t live there and never will, it’s fundamentally an external-provider
read, not an internal computation.
(b) Real adapters — GA4 and PostHog both, per the user’s explicit “both, not either/or.”
- PostHog: real Insights/Query API adapter, wrapping PostHog’s HogQL query endpoint (the
same account already used for event forwarding — confirm during implementation whether the
existing
POSTHOG_API_KEYhas query scope or whether a distinct personal/query-scoped API key is required per PostHog’s real, current docs; don’t assume). - GA4: real Google Analytics Data API (v1beta) adapter — requires a real GA4 property ID and service-account credentials. This is a real credential gate for live end-to-end verification, same disclosed-gap pattern this repo already uses for admin-auth-clerk (epic 27) — the adapter is built for real (correct request/response shapes verified against current, real Google API documentation, unit-tested against realistic mocked responses), but a live call against a real GA4 property can’t be proven in this environment without a real credential. Surface this honestly, don’t fake it.
- Internal source:
internal-bi’s existingBiMetricsAdapteris always one more available “source” for whatever it can answer (revenue/orders/products) — not a competing insights contract, just wired alongside the new external ones in the admin surface.
(c) Reconciling potentially conflicting numbers across sources. Resolved (already decided when this epic was first scoped, reconfirmed here): show every configured source side by side, explicitly labeled by source, never silently merged or summed. Different tools count things differently (bot filtering, session definitions, attribution windows) — presenting a single blended number would be actively misleading.
2. Scope assessment
Medium-large. One new contract + 2 real third-party adapter implementations + an admin UI surface. No schema change, no new persistence model — this is read-only, external-API-calling work plus a display surface.
3. Stories
- contract-and-posthog-adapter — the new
AnalyticsInsightsAdaptercontract (real methods:getTrafficSources,getPageViews,getTopReferrers, each over a real date range), a real PostHog adapter implementation against PostHog’s actual Query/Insights API. - ga4-adapter-and-admin-surface — a real GA4 Data API adapter (built against real,
current Google docs, credential-gated for live verification, disclosed honestly), and a new
“Traffic & Sources” section on
/admin/metricsshowing whichever sources are actually configured, side by side, never merged. - verification-and-closeout — verify whatever’s genuinely testable without external credentials (contract shape, admin UI’s not-configured/configured states, PostHog if a real key is available in this environment — check), disclose clearly what’s blocked on GA4 credentials, update the epic-38 BI deep-dive doc page, close out the backlog, merge.
4. Risks
- Medium — GA4’s live path can’t be fully proven without a real credential. Mitigation: explicit, honest disclosure per this repo’s own established pattern (epic 27’s admin-auth-clerk precedent) — the code is real and correct against real API docs, the live call is the disclosed gap, not silently claimed as verified.
- Low — PostHog’s query-scope requirement is unconfirmed until implementation. Mitigation: research this for real during story 1, don’t assume the existing write-side API key works.
5. Open questions
None blocking.