feat(gtm): Spec 1D — website reconciliation (analytics-foundation 1d)#365
Merged
Conversation
Routes every first-party event through per-app /api/ingest proxies and consolidates the analytics capture-guard helpers into @ngaf/telemetry so ad-blockers stop dropping marketing/docs/cockpit traffic and there's one source of truth across apps/website + apps/cockpit. Co-Authored-By: Claude Opus 4.7 <[email protected]>
While drafting the implementation plan, discovered the original spec conflated two distinct contracts: - /api/ingest serves libs/telemetry/browser's custom-envelope path (Spec 1B), accepting only ngaf:* events posted by consumer apps. - apps/website + apps/cockpit use posthog-js directly, which sends PostHog's batched/gzipped format to /e/, /flags/, /static/array.js, etc. — not the custom envelope. Revised architecture uses Next.js rewrites (PostHog's officially documented Next.js proxy pattern) at /ingest/* to forward transparently to us.i.posthog.com. The existing /api/ingest route is unchanged; the two paths serve different contracts side-by-side. Co-Authored-By: Claude Opus 4.7 <[email protected]>
…econciliation) Co-Authored-By: Claude Opus 4.7 <[email protected]>
…, getEmailDomain, getSourcePage, normalizePostHogHost) Moved from apps/website/src/lib/analytics/properties.ts so both shells + server-side code can consume one source of truth via @ngaf/telemetry/shared. Tests follow the code. Co-Authored-By: Claude Opus 4.7 <[email protected]>
…sHost Moved from apps/website/src/lib/analytics/properties.ts so apps/website and apps/cockpit consume the same capture guard via @ngaf/telemetry/browser. apps/cockpit's variant (which lacked the toSafeAnalyticsString hardening) is dropped in favor of this stricter implementation. Co-Authored-By: Claude Opus 4.7 <[email protected]>
…ry/shared
Switches server.ts + the four API routes (leads, ingest, whitepaper-signup,
newsletter) that use toSafeAnalyticsString, getEmailDomain, getSourcePage,
normalizePostHogHost to consume them from the published lib instead of the
app-local copy. Adds the @ngaf/telemetry/{shared,browser} path mappings to
the website tsconfig so Next.js bundler-mode resolution picks them up.
Local properties.ts stays until Task 0.5 deletes it.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
…/browser instrumentation-client.ts now sources the capture guard from the shared lib. Local properties.ts retains its remaining consumers (the test file itself) until Task 0.5. Co-Authored-By: Claude Opus 4.7 <[email protected]>
All consumers now import from @ngaf/telemetry/{shared,browser}. Tests
moved to libs/telemetry in Tasks 0.1 and 0.2.
Also migrates apps/website/src/lib/analytics/client.ts (browser-side
posthog-js capture helpers) to @ngaf/telemetry/shared — it was missed by
the Task 0.3 grep because it uses `from './properties'` rather than
`from '../analytics/properties'`.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
…y/browser Drops the cockpit-local properties.ts duplicate in favor of the website's stricter implementation now living in @ngaf/telemetry/browser. Both shells share one capture guard. Co-Authored-By: Claude Opus 4.7 <[email protected]>
- Export nextConfig as named export for testability - Add async rewrites() for /ingest/static and /ingest API paths - Set skipTrailingSlashRedirect to prevent ad-blocker bypass - Add next.config.spec.ts with rewrite rule validation
- Set api_host to '/ingest' for local proxy rewriting - Add ui_host pointing to us.posthog.com dashboard - Remove normalizePostHogHost import (no longer used)
Adds Next.js rewrites forwarding /ingest/static/* to us-assets.i.posthog.com and /ingest/* to us.i.posthog.com, plus CORS headers on /ingest/* so the embedded runtime iframe can POST analytics through the cockpit origin. Origin reads NEXT_PUBLIC_COCKPIT_IFRAME_ORIGIN (defaults to *). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Switches the cockpit's posthog-js api_host to '/ingest' (served by the proxy rewrites from §2.1) and sets ui_host to https://us.posthog.com so toolbar/replay links still resolve. Drops the now-unused NEXT_PUBLIC_COCKPIT_POSTHOG_HOST read from both client init paths. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
run-mode now defaults cockpit_host to {origin}/ingest so the embedded
Angular harness initializes posthog-js against the cockpit-served proxy.
NEXT_PUBLIC_COCKPIT_INGEST_HOST overrides for staging/preview origins.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…KPIT_IFRAME_ORIGIN Two new env vars introduced by Spec 1D: - NEXT_PUBLIC_COCKPIT_INGEST_HOST — absolute URL of the cockpit shell's /ingest proxy, written into the iframe URL's cockpit_host param. - NEXT_PUBLIC_COCKPIT_IFRAME_ORIGIN — CORS-allowed iframe origin for the cockpit's /ingest rewrite. NEXT_PUBLIC_COCKPIT_POSTHOG_HOST is removed — posthog-js now uses the same-origin /ingest rewrite (no host env needed). Co-Authored-By: Claude Opus 4.7 <[email protected]>
…Host Implementation already handles this form; test makes the coverage explicit. Co-Authored-By: Claude Opus 4.7 <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
blove
added a commit
that referenced
this pull request
Jun 9, 2026
…#365) * docs(gtm): spec for analytics-foundation-1d (website reconciliation) Routes every first-party event through per-app /api/ingest proxies and consolidates the analytics capture-guard helpers into @ngaf/telemetry so ad-blockers stop dropping marketing/docs/cockpit traffic and there's one source of truth across apps/website + apps/cockpit. Co-Authored-By: Claude Opus 4.7 <[email protected]> * docs(gtm): revise Spec 1D to use Next.js rewrites for posthog-js proxy While drafting the implementation plan, discovered the original spec conflated two distinct contracts: - /api/ingest serves libs/telemetry/browser's custom-envelope path (Spec 1B), accepting only ngaf:* events posted by consumer apps. - apps/website + apps/cockpit use posthog-js directly, which sends PostHog's batched/gzipped format to /e/, /flags/, /static/array.js, etc. — not the custom envelope. Revised architecture uses Next.js rewrites (PostHog's officially documented Next.js proxy pattern) at /ingest/* to forward transparently to us.i.posthog.com. The existing /api/ingest route is unchanged; the two paths serve different contracts side-by-side. Co-Authored-By: Claude Opus 4.7 <[email protected]> * docs(gtm): implementation plan for analytics-foundation-1d (website reconciliation) Co-Authored-By: Claude Opus 4.7 <[email protected]> * feat(telemetry): add shared properties helpers (toSafeAnalyticsString, getEmailDomain, getSourcePage, normalizePostHogHost) Moved from apps/website/src/lib/analytics/properties.ts so both shells + server-side code can consume one source of truth via @ngaf/telemetry/shared. Tests follow the code. Co-Authored-By: Claude Opus 4.7 <[email protected]> * feat(telemetry): add browser shouldCaptureAnalytics + isLocalAnalyticsHost Moved from apps/website/src/lib/analytics/properties.ts so apps/website and apps/cockpit consume the same capture guard via @ngaf/telemetry/browser. apps/cockpit's variant (which lacked the toSafeAnalyticsString hardening) is dropped in favor of this stricter implementation. Co-Authored-By: Claude Opus 4.7 <[email protected]> * refactor(website): import shared analytics helpers from @ngaf/telemetry/shared Switches server.ts + the four API routes (leads, ingest, whitepaper-signup, newsletter) that use toSafeAnalyticsString, getEmailDomain, getSourcePage, normalizePostHogHost to consume them from the published lib instead of the app-local copy. Adds the @ngaf/telemetry/{shared,browser} path mappings to the website tsconfig so Next.js bundler-mode resolution picks them up. Local properties.ts stays until Task 0.5 deletes it. Co-Authored-By: Claude Opus 4.7 <[email protected]> * refactor(website): import shouldCaptureAnalytics from @ngaf/telemetry/browser instrumentation-client.ts now sources the capture guard from the shared lib. Local properties.ts retains its remaining consumers (the test file itself) until Task 0.5. Co-Authored-By: Claude Opus 4.7 <[email protected]> * refactor(website): delete duplicated analytics/properties.ts All consumers now import from @ngaf/telemetry/{shared,browser}. Tests moved to libs/telemetry in Tasks 0.1 and 0.2. Also migrates apps/website/src/lib/analytics/client.ts (browser-side posthog-js capture helpers) to @ngaf/telemetry/shared — it was missed by the Task 0.3 grep because it uses `from './properties'` rather than `from '../analytics/properties'`. Co-Authored-By: Claude Opus 4.7 <[email protected]> * refactor(cockpit): consume shouldCaptureAnalytics from @ngaf/telemetry/browser Drops the cockpit-local properties.ts duplicate in favor of the website's stricter implementation now living in @ngaf/telemetry/browser. Both shells share one capture guard. Co-Authored-By: Claude Opus 4.7 <[email protected]> * feat(website): add /ingest/* rewrites to posthog proxy (#1D.1) - Export nextConfig as named export for testability - Add async rewrites() for /ingest/static and /ingest API paths - Set skipTrailingSlashRedirect to prevent ad-blocker bypass - Add next.config.spec.ts with rewrite rule validation * feat(website): point posthog-js at /ingest proxy (#1D.2) - Set api_host to '/ingest' for local proxy rewriting - Add ui_host pointing to us.posthog.com dashboard - Remove normalizePostHogHost import (no longer used) * feat(cockpit): /ingest rewrites + CORS for iframe posthog-js Adds Next.js rewrites forwarding /ingest/static/* to us-assets.i.posthog.com and /ingest/* to us.i.posthog.com, plus CORS headers on /ingest/* so the embedded runtime iframe can POST analytics through the cockpit origin. Origin reads NEXT_PUBLIC_COCKPIT_IFRAME_ORIGIN (defaults to *). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * feat(cockpit): point posthog-js at /ingest proxy Switches the cockpit's posthog-js api_host to '/ingest' (served by the proxy rewrites from §2.1) and sets ui_host to https://us.posthog.com so toolbar/replay links still resolve. Drops the now-unused NEXT_PUBLIC_COCKPIT_POSTHOG_HOST read from both client init paths. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * feat(cockpit): pass /ingest proxy host to iframe runtime run-mode now defaults cockpit_host to {origin}/ingest so the embedded Angular harness initializes posthog-js against the cockpit-served proxy. NEXT_PUBLIC_COCKPIT_INGEST_HOST overrides for staging/preview origins. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * docs(env): document NEXT_PUBLIC_COCKPIT_INGEST_HOST + NEXT_PUBLIC_COCKPIT_IFRAME_ORIGIN Two new env vars introduced by Spec 1D: - NEXT_PUBLIC_COCKPIT_INGEST_HOST — absolute URL of the cockpit shell's /ingest proxy, written into the iframe URL's cockpit_host param. - NEXT_PUBLIC_COCKPIT_IFRAME_ORIGIN — CORS-allowed iframe origin for the cockpit's /ingest rewrite. NEXT_PUBLIC_COCKPIT_POSTHOG_HOST is removed — posthog-js now uses the same-origin /ingest rewrite (no host env needed). Co-Authored-By: Claude Opus 4.7 <[email protected]> * test(telemetry): cover bracketed IPv6 [::1]:port for isLocalAnalyticsHost Implementation already handles this form; test makes the coverage explicit. Co-Authored-By: Claude Opus 4.7 <[email protected]> --------- Co-authored-by: Claude Opus 4.7 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Spec 1D closes analytics-foundation. Two cohesive changes:
The existing `/api/ingest` route (Spec 1B's `libs/telemetry/browser` custom envelope path) is untouched — it serves a different contract for consumer apps' opt-in browser telemetry.
Spec & Plan
Notable design notes
Test plan
🤖 Generated with Claude Code