Skip to content

feat(self-host): make vendor telemetry, endpoints, and support staff configurable - #1

Open
kopertop wants to merge 1 commit into
mainfrom
feature/self-host-telemetry-and-endpoint-config
Open

feat(self-host): make vendor telemetry, endpoints, and support staff configurable#1
kopertop wants to merge 1 commit into
mainfrom
feature/self-host-telemetry-and-endpoint-config

Conversation

@kopertop

Copy link
Copy Markdown
Member

Why

A self-hosted build of this repo currently ships Macro's own marketing stack and points itself at macro.com, and none of it is gated on anything an operator can set. The defaults fail toward the vendor rather than toward the deployment.

The concrete leak: apps/web/src/lib/analytics/providers.ts injected Macro's GA4, GTM, Google Ads, and Meta Pixel ids with the only guard being import.meta.env.DEV === true (analytics.ts:167). DEV is true only under the Vite dev server — this repo's own headless stack builds with bun run build + NODE_ENV=production (tooling/xtask/.../frontend.rs:56-63), so DEV is false and all four trackers were live. identify() then sent each user's email address to Google in cleartext and to Meta via fbq('init', …, {em}), landing in Macro's analytics property and pixel.

What changed

Third-party analytics ids → build env (new apps/web/src/lib/analytics/config.ts)

VITE_GA_MEASUREMENT_ID, VITE_GTM_CONTAINER_ID, VITE_GOOGLE_ADS_ID, VITE_META_PIXEL_ID. Absent means the script is never injected and no request reaches the vendor — the same shape PostHog already had via VITE_POSTHOG_API_KEY. Every gtag/fbq call site is guarded, so no console noise when the globals don't exist. Macro's own builds get the ids from CI (deploy_web_app.yml, regenerated from its xtask source).

Backend origin honored in any build mode (servers.ts)

SERVER_HOSTS previously ignored the proxy origin unless MODE === 'development', so a plain vite build produced a client pinned to *.macro.com with no override. Now VITE_BACKEND_ORIGIN (or the existing VITE_LOCAL_BACKEND_ORIGIN) applies in any mode, sync-service included, plus VITE_AUTH_LOGOUT_URL for a self-hosted FusionAuth tenant. Unset → serverHostRemote, unchanged.

Support team → config (SUPPORT_CHANNEL_HOST / SUPPORT_CHANNEL_MEMBERS)

create_user_webhook.rs hardcoded jacob@, julia@, teo@macro.com into every new user's support channel. Macro user ids are email-derived (macro|<email>), so on a self-hosted instance with open signup, whoever registers one of those addresses lands on an identity that already holds membership in every user's private support channel. Now resolved from config at startup (bad value fails startup, not every signup); unset → no support channel is created, and starter-doc seeding still runs.

Entry format is email[:label], where the label is the parenthetical in the welcome copy. Macro's own configuration is SUPPORT_CHANNEL_HOST=julia@macro.com:julia, SUPPORT_CHANNEL_MEMBERS=jacob@macro.com:ceo,teo@macro.com:ctoneeds adding to Doppler before this deploys, or new users silently stop getting support channels.

Loud ENVIRONMENT fallback (macro_env)

new_or_prod() returning Production for unset config makes every macro_service_urls lookup resolve to *.macro.com. Still does, but now warns once with the fix. No call-site churn.

Verification

  • Self-host-style build (MODE=development NODE_ENV=production, the xtask stack's flags): zero occurrences of G-52HPEL3FTV, GTM-M58X7PJ8, AW-11035820781, 639142540393286, and no googletagmanager.com / connect.facebook.net in the emitted JS (sourcemap only).
  • Control build with the four ids set, as CI passes them: all four present. Prod behavior preserved.
  • bun run type-check clean; biome check clean.
  • cargo check/clippy -p macro_env -p authentication_service --tests clean; cargo test -p authentication_service --lib support_ → 9 passed, including the pre-existing posts_the_welcome_message test that asserts the exact welcome string — so the deployed copy is byte-identical under the config above.
  • cargo x workflows --check → "all generated workflows are up to date".

Deliberately out of scope

Flagging rather than changing: the analytics proxy renames posthog-recorder.jsruntime.js specifically to evade tracker blockers (services/analytics-proxy/src/index.ts:23-26) — inert when self-hosting since there's no key, but the intent is deliberate and worth a separate decision. Tauri's CSP is null. proxyServers() still falls back to localhost for pdf-service / scheduled-action, which have no local container.

…configurable

A self-hosted build currently ships Macro's own marketing stack and points
itself at macro.com. None of it is gated on anything an operator can set.

- analytics: move the GA4 / GTM / Google Ads / Meta Pixel ids out of the
  source and into VITE_* build env (new apps/web/src/lib/analytics/config.ts).
  Absent => the script is never injected, matching how PostHog is already
  gated. The only prior guard was `import.meta.env.DEV`, which is false in
  every real build — including the repo's own headless stack — so the
  sanctioned self-host bundle sent page views and user emails to Macro's GA
  property and Meta pixel. Macro's deploys inject the ids in CI.
- servers: honor an explicit backend origin (VITE_BACKEND_ORIGIN, or the
  existing VITE_LOCAL_BACKEND_ORIGIN) in any build mode, not just
  MODE=development, and add VITE_AUTH_LOGOUT_URL. A production-mode bundle
  was otherwise hardwired to *.macro.com with no override path.
- support channels: replace the hardcoded jacob@/julia@/teo@macro.com
  constants with SUPPORT_CHANNEL_HOST / SUPPORT_CHANNEL_MEMBERS. Unset =>
  no support channel. User ids are email-derived, so a fork seeding those
  addresses grants whoever registers them membership in every user's private
  support channel.
- macro_env: warn once when ENVIRONMENT is unset and new_or_prod() falls back
  to Production, which silently resolves every service URL to *.macro.com.

Behavior for Macro's own dev/prod deploys is unchanged: the CI build passes
the same ids, and the welcome-message test asserts byte-identical copy from
the equivalent SUPPORT_CHANNEL_* config.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant