Skip to content

FRD: Analytics Provider Wrapper

Document Summary

FieldDetails
Feature NameAnalytics Provider Wrapper
StatusDraft
OwnerDavid Holmes
ContributorsEngineering
Target Releasev2.0.0
Related LinksADR-051 (Provider Pattern), ADR-027 (Default Tech Stack), ADR-014 (Open Source First)
Last Updated2026-06-02
Open Source Librariesposthog-js, posthog-node
DocumentationPostHog JS Docs · PostHog Node Docs · Event Capture

This FRD ships @dmwd-io/analytics as an optional package that re-exports posthog-js and posthog-node as the platform standard for product analytics via PostHog. The value is standards and drift prevention, not a custom abstraction. No custom provider interface is built — the library’s own API is the interface, per ADR-014.


Introduction

Overview

Per ADR-014 (Open Source First), the platform designates posthog-js and posthog-node as the community libraries for product analytics rather than building a custom AnalyticsProvider interface. The @dmwd-io/analytics package re-exports these libraries as thin wrappers and documents the platform env var conventions (POSTHOG_API_KEY, POSTHOG_HOST). Apps that today scatter direct PostHog imports or use inconsistent event naming conventions converge on a single import path and documented conventions without an extra abstraction layer.

Goals

  • Designate posthog-js / posthog-node as the platform standard for product analytics per ADR-027 §5 and ADR-014.
  • Ship @dmwd-io/analytics as a thin re-export package so all apps import from one canonical path.
  • Document POSTHOG_API_KEY and POSTHOG_HOST as the platform env var names.
  • Enforce an event naming convention ({domain}.{action}) matching the wide-events standard from ADR-023.
  • Document privacy-conscious defaults: no PII in event properties unless explicitly opted in.
  • Include examples showing standard PostHog integration using the @dmwd-io/analytics import path.

Non-Goals

  • Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).
  • Mixpanel or Google Analytics adapters (not designated by ADR-027).
  • Implementing a custom mock adapter — use PostHog’s built-in testing utilities or vi.mock.
  • Building analytics dashboards or reporting UI.
  • A/B test assignment or experiment tracking (see FRD: Feature Flags Provider).
  • Revenue or conversion tracking beyond standard event properties.

Scope

In Scope

AreaDescription
@dmwd-io/analytics packageThin re-export of posthog-js and posthog-node; canonical import path for all apps
Env var conventionsPOSTHOG_API_KEY and POSTHOG_HOST documented as platform standard names
Privacy defaultsDocumentation of PII-safe defaults; guidance on avoiding PII in event properties
Event namingConvention: {domain}.{action} format per ADR-023; documented, not enforced at runtime
Integration examplesStorybook docs showing PostHog initialization and event calls via @dmwd-io/analytics

Out of Scope

AreaReason
Custom provider interfaceADR-014 prohibits building one when the community library’s API suffices
Custom adapter or factory patternLibrary handles this natively
Mixpanel or Google Analytics adaptersNot designated by ADR-027
Custom mock adapterUse PostHog’s testing utilities or vi.mock
Analytics dashboardsVendor-hosted
A/B test trackingCovered by feature flags provider
Session recordingSeparate vendor capability

Users and Pain Points

User Groups

UserDescriptionNeeds
App developersEngineers instrumenting product analyticsA canonical import path and documented conventions for PostHog
QA engineersTesters verifying analytics fire correctlyClear guidance on mocking PostHog in tests
Product managersStakeholders analyzing user behaviorConsistent event naming and property schemas across apps

Pain Points

UserPain PointImpact
App developersEach app imports PostHog directly with different initialization patternsInconsistent configuration; env var names vary across apps
App developersNo shared guidance on testing analytics callsAnalytics regressions (missing events, wrong properties) go undetected
Product managersEvent names vary across apps — button_click vs ButtonClicked vs ui.button.clickDashboard queries break; analysis requires manual name mapping
App developersPII accidentally ends up in analytics events (email in properties, names in traits)Privacy compliance violations

Definitions

TermDefinition
TrackRecord a named event with properties (e.g. billing.plan_upgraded)
IdentifyAssociate the current user with a user ID and traits (name, plan, role)
GroupAssociate the current user with a group/organization with traits
PageRecord a page view with URL and properties
ResetClear the current user identity (on sign-out)
ConsentUser’s opt-in/opt-out status for analytics collection
PIIPersonally identifiable information: email, phone, IP address, full name

Current State

Existing Behavior

No shared analytics abstraction exists. Apps import posthog-js or other vendor SDKs directly in components and utility files. Event names, property schemas, and user identification patterns vary across apps. No privacy safeguards exist at the analytics layer — developers must manually avoid passing PII.

Current Limitations

  • No canonical import path — apps wire PostHog with different initialization patterns.
  • No documented env var names — POSTHOG_API_KEY vs NEXT_PUBLIC_POSTHOG_KEY vs other names appear across apps.
  • No event naming convention — each app invents its own schema.
  • No PII guidance — sensitive data leaks into analytics properties.
  • No shared testing guidance — tests mock PostHog globals inconsistently.

Existing Workarounds

  • Apps create ad-hoc wrapper functions around PostHog calls.
  • Test files mock window.posthog globals inconsistently.
  • Privacy reviews manually audit analytics calls before release.

Proposed Solution

Summary

Per ADR-014 (Open Source First), @dmwd-io/analytics is a thin re-export package. It re-exports posthog-js and posthog-node as-is, documents the platform env var names (POSTHOG_API_KEY, POSTHOG_HOST), and provides usage examples. No custom interface is built — the library’s API is the interface.

import { PostHog } from '@dmwd-io/analytics';

The package adds platform conventions on top of the library without wrapping or replacing it.

Key Capabilities

  • @dmwd-io/analytics re-exports posthog-js (browser) and posthog-node (server) from a single package.
  • Platform env var names: POSTHOG_API_KEY and POSTHOG_HOST.
  • Event naming convention documented: {domain}.{action} per ADR-023.
  • PII guidance documented: avoid email, phone, ip, ssn keys in event properties.
  • No custom runtime code beyond the re-export and any platform-specific initialization helper.

User Experience

End users are not directly affected. The package powers analytics instrumentation behind the scenes. Users benefit from privacy-conscious defaults documented for developers.

Developer Experience

Developers import from @dmwd-io/analytics instead of posthog-js directly. Initialization follows the documented POSTHOG_API_KEY / POSTHOG_HOST pattern. Event naming follows {domain}.{action}. Testing uses PostHog’s own test utilities or vi.mock — no custom mock adapter is needed.


Requirements

IDRequirementPriorityNotes
FR-001@dmwd-io/analytics re-exports posthog-js and posthog-nodeMust-
FR-002Platform env var names POSTHOG_API_KEY and POSTHOG_HOST are documentedMust-
FR-003Event naming convention {domain}.{action} is documented with examplesMustPer ADR-023
FR-004PII avoidance guidance is documented for event propertiesMust-
FR-005Storybook docs page shows PostHog initialization using @dmwd-io/analyticsMust-
FR-006Testing guidance documents how to mock PostHog using vi.mock or PostHog test utilitiesShould-

Priority Definitions

PriorityMeaning
MustRequired for this feature to ship.
ShouldImportant, but can be deferred if needed.
CouldNice to have. Not required for initial release.

Functional Requirements

IDRequirementUser BenefitPriority
FUNC-001import { posthog } from '@dmwd-io/analytics' works in browser contextsSingle import path for all appsMust
FUNC-002import { PostHog } from '@dmwd-io/analytics/node' works in server/Node contextsServer-side analytics via the same packageMust
FUNC-003Docs show posthog.identify(userId, { name, plan }) with PII guidanceUser-level analytics with privacy contextMust
FUNC-004Docs show posthog.capture('billing.plan_upgraded', { planId }) with naming conventionConsistent event tracking across appsMust
FUNC-005Docs show PostHog initialization using POSTHOG_API_KEY and POSTHOG_HOSTConsistent env var usage across appsMust
FUNC-006Docs show how to mock PostHog in Vitest using vi.mockTest-time analytics verificationShould

Non-Functional Requirements

IDRequirementCategoryPriority
NFR-001The package adds zero custom runtime code beyond the re-exportMaintainabilityMust
NFR-002posthog-js and posthog-node are peer dependencies, not bundledPerformanceMust
NFR-003Package does not introduce a breaking API change relative to posthog-jsCompatibilityMust
NFR-004Analytics calls must never throw — this is posthog-js’s own behavior, documentedReliabilityMust

API / Interface Requirements

Public API

The public API is posthog-js / posthog-node’s own API, re-exported. No new types or functions are added by the package itself. The platform layer adds only:

NameTypeDescription
POSTHOG_API_KEYenv varPostHog project API key
POSTHOG_HOSTenv varPostHog instance host URL (e.g. https://app.posthog.com)

Example Usage

// Browser (React, Astro client components)
import posthog from '@dmwd-io/analytics';
posthog.init(process.env.POSTHOG_API_KEY, {
api_host: process.env.POSTHOG_HOST,
});
posthog.identify('user_123', { name: 'Alice', plan: 'pro' });
posthog.capture('billing.plan_upgraded', { planId: 'pro' });
// Server / Node (Go BFF, Astro SSR)
import { PostHog } from '@dmwd-io/analytics/node';
const client = new PostHog(process.env.POSTHOG_API_KEY, {
host: process.env.POSTHOG_HOST,
});
client.capture({ distinctId: 'user_123', event: 'billing.plan_upgraded', properties: { planId: 'pro' } });

API Notes

  • The library’s API is the interface — no wrapper functions are exported.
  • PII fields (email, phone, ip) should be omitted from event properties; PostHog person profiles handle identity separately.
  • Event names follow {domain}.{action} per ADR-023.

Accessibility Requirements

IDRequirementNotes
A11Y-001Package is a data layer with no UI — accessibility requirements do not apply directlyNo UI components

Checklist

  • Keyboard support is defined. (N/A — no UI)
  • Focus behavior is defined. (N/A — no UI)
  • Screen reader behavior is defined. (N/A — no UI)
  • Color contrast requirements are met. (N/A — no UI)
  • Reduced motion behavior is considered. (N/A — no UI)
  • Semantic HTML expectations are documented. (N/A — no UI)
  • ARIA usage is defined only where needed. (N/A — no UI)

Content and Documentation Requirements

IDRequirementLocationPriority
DOC-001Storybook docs page explaining the platform standard and @dmwd-io/analytics import pathStorybookMust
DOC-002Env var reference: POSTHOG_API_KEY, POSTHOG_HOSTStorybookMust
DOC-003Example: browser initialization and event captureStorybookMust
DOC-004Example: server-side initialization with posthog-nodeStorybookMust
DOC-005Example: testing analytics calls with vi.mockStorybookShould
DOC-006PII avoidance guidance with concrete do/don’t examplesStorybookMust

Dependencies

DependencyTypeOwnerStatusNotes
ADR-051 provider patternArchitectureEngineeringReadyDefines contract structure
ADR-023 wide events loggingArchitectureEngineeringReadyDefines {domain}.{action} naming convention
ADR-027 default tech stackArchitectureEngineeringReadyDesignates PostHog (self-host) as the product analytics default
ADR-014 open source firstArchitectureEngineeringReadyRequires adopting community library API rather than building custom interface

Risks and Tradeoffs

Risk / TradeoffImpactMitigation
posthog-js API changes break consuming appsBreaking change propagates through @dmwd-io/analyticsPin a major version range; document upgrade path
PII guidance is documentation-only, not enforced at runtimeSensitive data may still leakLint rule or PR checklist item to review analytics calls
Thin re-export adds little value if apps ignore the canonical importDrift continuesEnforce via lint rule requiring @dmwd-io/analytics import, not direct posthog-js
No server-side analytics in v1Server-rendered pages cannot track eventsposthog-node re-export covers this natively

Open Questions

IDQuestionOwnerStatusResolution
Q-001Should the package export a platform-specific initPostHog helper to enforce env var names?David HolmesOpen
Q-002Should the PII guidance be enforced via an ESLint rule rather than documentation?David HolmesOpen
Q-003Should @dmwd-io/analytics be a separate npm package or a path export from the design system?David HolmesOpen

Acceptance Criteria

IDCriteriaRelated Requirement
AC-001import posthog from '@dmwd-io/analytics' resolves to posthog-js without errorFR-001
AC-002import { PostHog } from '@dmwd-io/analytics/node' resolves to posthog-node without errorFR-001
AC-003POSTHOG_API_KEY and POSTHOG_HOST are documented as the platform env var namesFR-002
AC-004Storybook docs page shows initialization and event capture examplesFR-005
AC-005No custom provider interface, adapter, or factory function is shipped in the packageADR-014
AC-006pnpm typecheck passes with no errorsNFR-001

LLM Handoff Instructions

Expected LLM Behavior

  • Create the @dmwd-io/analytics package (or path export) structure.
  • Add a package.json with posthog-js and posthog-node as peer dependencies.
  • Create src/index.ts that does export { default } from 'posthog-js'; export * from 'posthog-js';.
  • Create src/node.ts that does export * from 'posthog-node';.
  • Document POSTHOG_API_KEY and POSTHOG_HOST as the platform env var names in the Storybook docs page.
  • Run pnpm typecheck to confirm no type errors.

LLM Should Not

  • Build a custom AnalyticsProvider interface, adapter, factory function, or mock — per ADR-014.
  • Import posthog-js or posthog-node anywhere except the re-export files.
  • Add runtime logic beyond the re-export and any optional initialization helper.
  • Build Mixpanel or Google Analytics adapters.

Decision Log

DateDecisionReasonOwner
2026-05-26Fire-and-forget (synchronous void) APIAnalytics must never block UI rendering or throw errors that break the appDavid Holmes
2026-05-26PII sanitizer enabled by defaultPrivacy-by-default is the correct stance; developers can opt in to sending PII explicitlyDavid Holmes
2026-05-26{domain}.{action} event naming per ADR-023Consistent naming across analytics and logging enables cross-system correlationDavid Holmes
2026-05-26PostHog designated as the analytics adapterADR-027 §5 designates PostHog (self-host) as the product analytics default; separate from wide-event loggingDavid Holmes
2026-06-02Reframed per ADR-014 (Open Source First): adopt posthog-js / posthog-node as thin re-export rather than building a custom provider interface. Library API is the interface.ADR-014 prohibits building custom abstractions when a well-maintained community library covers the use caseDavid Holmes

Document History

DateAuthorChange
2026-05-26David HolmesInitial draft
2026-06-02David HolmesReframed per ADR-014: ship as thin re-export of posthog-js / posthog-node, drop custom interface.