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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…econciliation) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…, 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 <noreply@anthropic.com>
…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 <noreply@anthropic.com>
…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 <noreply@anthropic.com>
…/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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…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 <noreply@anthropic.com>
- 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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
…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 <noreply@anthropic.com>
…Host Implementation already handles this form; test makes the coverage explicit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * docs(gtm): implementation plan for analytics-foundation-1d (website reconciliation) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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) <noreply@anthropic.com> * 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) <noreply@anthropic.com> * 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) <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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