Removed all components that served Highlight's SaaS business but have no value for self-hosted deployments. 1,056 files changed — ~82,800 lines deleted.
What it was: CRM tracking — synced workspace/admin data to HubSpot, tracked session views, merged duplicate contacts ("doppelgänger" detection).
Deleted:
/src/backend/hubspot/—hubspot.go,merge.go
Modified:
/src/backend/env/environment.go— removedHubspotApiKey,HubspotCookieString,HubspotCsrfToken,HubspotOAuthTokenfromConfiguration/src/backend/model/model.go— removedHubspotCompanyIDfromWorkspace,HubspotContactIDfromAdmin/src/backend/redis/utils.go— removedCacheKeyHubspotCompanies,SetHubspotCompanies,GetHubspotCompanies/src/backend/kafka-queue/types.go— replaced 5 deprecated HubSpotPayloadTypeconstants with blank_identifiers (preserves iota numbering)/src/backend/private-graph/graph/schema.resolvers.go— cleaned "hubspot" from log messages/src/backend/worker/worker.go— cleaned "hubspot" from log messages/src/backend/public-graph/graph/resolver.go— removed HubSpot mention from comment/src/frontend/src/util/analytics.ts— removedwindow._hsqtracking/src/frontend/src/@types/window.d.ts— removed_hsqtype
Env vars removed: HUBSPOT_API_KEY, HUBSPOT_COOKIE_STRING, HUBSPOT_CSRF_TOKEN, HUBSPOT_OAUTH_TOKEN
What it was: Contact enrichment on admin signup — looked up email via Apollo.io API, created contacts in Apollo, added them to sales email sequences.
Deleted:
/src/backend/apolloio/—apolloio.go
Modified:
/src/backend/env/environment.go— removedApolloIoAPIKey,ApolloIoSenderID/src/backend/private-graph/graph/schema.resolvers.go— removedapolloio.Enrich(),apolloio.CreateContact(),apolloio.AddToSequence()fromEmailSignupresolver; resolver now just saves the email/src/backend/model/model.go— removedApolloData,ApolloDataShortenedfromEmailSignupstruct
Env vars removed: APOLLO_IO_API_KEY, APOLLO_IO_SENDER_ID
What it was: Company data enrichment from email/IP — used for lead scoring. Gated behind Premium/Startup/Enterprise tiers.
Deleted:
/src/frontend/src/pages/IntegrationsPage/components/ClearbitIntegration/— 3 files/src/frontend/src/clearbit.js— tracking script/src/frontend/src/static/integrations/clearbit.svg— logo
Modified:
/src/backend/pricing/pricing.go— removedMustUpgradeForClearbit()/src/backend/env/environment.go— removedClearbitApiKey/src/backend/main.go— removed clearbit client initialization/src/backend/private-graph/graph/resolver.go— removedClearbitClientfield and import/src/backend/private-graph/graph/schema.resolvers.go— stubbedModifyClearbitIntegration(returns true), stubbedEnhancedUserDetails(returns nil)/src/frontend/index.html— removed clearbit script tag/src/frontend/src/pages/IntegrationsPage/Integrations.tsx— removed Clearbit from integrations list/src/frontend/src/pages/IntegrationsPage/IntegrationsPage.tsx— removed Clearbit hooks/state/src/frontend/src/util/billing/billing.ts— removedmustUpgradeForClearbit()/src/frontend/src/pages/Player/MetadataBox/MetadataBox.tsx— removed Clearbit tooltip mention
Env vars removed: CLEARBIT_API_KEY
Note: ClearbitEnabled bool left on Workspace struct (inert DB column — removing requires migration).
What it was: Sent usage metrics (workspace counts, session counts, admin details) back to Highlight's own OpenTelemetry endpoint for internal analytics.
Deleted:
/src/backend/phonehome/—phonehome.go
Modified:
/src/backend/main.go— removedphonehome.Start(ctx)call/src/backend/public-graph/graph/resolver.go— removedphonehome.ReportUsageMetricscall/src/backend/private-graph/graph/schema.resolvers.go— removed allphonehome.ReportUsageMetricsandphonehome.ReportAdminAboutYouDetailscalls (4+ sites), removedPhoneHomeContactAllowedassignment/src/backend/worker/worker.go— removed entire phonehome reporting section fromRefreshMaterializedViews/src/backend/private-graph/graph/schema.graphqls— removedphone_home_contact_allowedfromAdminAboutYouDetailsandAdminAndWorkspaceDetailsinput types/src/backend/model/model.go— removedPhoneHomeContactAllowedfromAdminstruct/src/backend/private-graph/graph/model/models_gen.go— removed field from generated types/src/backend/private-graph/graph/generated/generated.go— removed from schema/unmarshal/src/backend/projectpath/config.go— removedPhoneHomeDeploymentIDfromConfig
What it was: Full subscription management — Stripe customer creation, plan selection, graduated pricing, usage-based billing, overage detection, billing issue banners, promo codes.
Strategy: Kept /src/backend/pricing/ package (meter query functions are used by non-billing code) but gutted all Stripe API calls and billing logic.
Deleted:
/src/backend/lambda-functions/metering/— AWS Marketplace metering Lambda
Modified:
/src/backend/env/environment.go— removedPricingBasicPriceID,PricingEnterprisePriceID,PricingStartupPriceID,StripeApiKey,StripeErrorsProductID,StripeSessionsProductID,StripeWebhookSecret/src/backend/pricing/pricing.go— gutted. Kept: price tables, meter query functions,RetentionMultiplier,IncludedAmount. Removed: ALL Stripe API calls, AWS Marketplace functions, overage reporting, billing issue detection (~1000+ lines)/src/backend/pricing/billing.go— replaced entirely with minimalClientstruct andNewNoopClient()/src/backend/public-graph/graph/resolver.go—IsWithinQuotanow always returns(true, 0)— this is the critical change making all data ingestion unlimited/src/backend/private-graph/graph/resolver.go— removedPricingClient,AWSMPClientfields; stubbedStripeWebhook,AWSMPCallback,updateBillingDetailsas no-ops/src/backend/private-graph/graph/schema.resolvers.go— stubbed:CreateOrUpdateStripeSubscription(returns ""),HandleAWSMarketplace(returns true),UpdateBillingDetails(returns true),SubscriptionDetails(returns enterprise defaults),CustomerPortalURL(returns ""); removed Stripe customer creation fromCreateWorkspace/src/backend/main.go— removed pricing/Stripe/AWS MP client initialization/src/backend/worker/worker.go—ReportStripeUsageis now a no-op; removed periodic reporting goroutine/src/backend/migrations/cmd/add-stripe-prices/main.go— gutted to no-op
Env vars removed: STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_ERRORS_PRODUCT_ID, STRIPE_SESSIONS_PRODUCT_ID, BASIC_PLAN_PRICE_ID, ENTERPRISE_PLAN_PRICE_ID, STARTUP_PLAN_PRICE_ID
What it was: Usage metering for reselling Highlight through AWS Marketplace.
Deleted:
/src/backend/lambda-functions/metering/— entire Lambda function
Modified:
- Covered above in Stripe/Billing section (client removed from resolver, main.go, etc.)
What it was: Feature flag SDK integrated right before Highlight's shutdown. Included a migration gate that blocked users whose workspaces hadn't been migrated to LaunchDarkly.
Modified (Frontend):
/src/frontend/src/components/LaunchDarkly/LaunchDarklyProvider.tsx— replaced with pass-through provider (no LD SDK, noops for context setters)/src/frontend/src/components/LaunchDarkly/useFeatureFlag.ts— replaced with stub returningflags[flag].defaultValue/src/frontend/src/components/LaunchDarkly/useFeatureFlag.test.ts— updated tests/src/frontend/src/util/analytics.ts— removedLDClient,setLDClient,ldClient.track()/src/frontend/src/index.tsx— removedMigrationBlockedPage,isMigrationBlockedError, LD migration UI/src/frontend/src/pages/Auth/SignUp.tsx— removed "Creating new workspaces is disabled" callout/src/frontend/src/pages/Auth/JoinWorkspace.tsx— removed LD migration callouts/src/frontend/src/routers/AppRouter/AppRouter.tsx— removed/demoredirect to launchdarkly.com/src/frontend/src/env.d.ts— removedREACT_APP_LD_CLIENT_ID/src/frontend/package.json— removedlaunchdarkly-react-client-sdkdependency/src/frontend/src/graph/operators/query.gql— removedmigration_allowlistfromGetSystemConfiguration/src/frontend/src/graph/generated/— removedmigration_allowlistfrom generated types
Modified (Backend):
/src/backend/private-graph/graph/middleware.go— removedmigrationBlockedResponse,isUserInAllowedWorkspace,writeMigrationBlockedError, migration checks inPrivateMiddlewareandWebsocketInitializationFunction/src/backend/model/model.go— removedMigrationAllowlistfromSystemConfiguration/src/backend/private-graph/graph/schema.graphqls— removedmigration_allowlistfromSystemConfigurationtype/src/backend/private-graph/graph/schema.resolvers.go— removedMigrationAllowlistresolver/src/backend/private-graph/graph/generated/generated.go— removed all generated migration_allowlist references
What it was: Next.js marketing site — landing pages, blog, Calendly scheduling, Mux video. Not the app dashboard.
Deleted:
/highlight.io/— entire directory (~1000 files)
Modified:
/package.json— removedhighlight.iofrom workspaces, removeddev:highlight.ioscript/turbo.json— removedhighlight.io#buildandhighlight.io#linttask configs/.changeset/config.json— removedhighlight.iofrom ignore list
/src/backend/model/model.go — AllWorkspaceSettings struct:
All feature flag defaults changed from false to true:
AIInsights,AIQueryBuilderEnableBillingLimits,EnableGrafanaDashboard,EnableIngestSamplingEnableJiraIntegration,EnableTeamsIntegrationEnableProjectLevelAccess,EnableSessionExport,EnableSSOEnableUnlimitedDashboards,EnableUnlimitedProjects,EnableUnlimitedRetention,EnableUnlimitedSeatsEnableLogTraceIngestion
CanShowBillingIssueBanner default changed to false.
Effect: All new workspaces get every feature enabled. Existing workspaces need a DB update or re-run of EnableAllWorkspaceSettings.
These steps should be run before committing but haven't been executed yet:
-
cd backend && go mod tidy— remove unused Go deps (clearbit-go, stripe-go, AWS marketplace SDK) -
make private-gen— regenerate backend GraphQL after schema changes -
yarn install— update lockfile after removing LD SDK -
yarn codegen— regenerate frontend GraphQL types -
cd frontend && yarn types:check— verify no TypeScript errors -
cd backend && go build ./...— final compilation check (currently passes)
| Variable | Component |
|---|---|
HUBSPOT_API_KEY |
HubSpot |
HUBSPOT_COOKIE_STRING |
HubSpot |
HUBSPOT_CSRF_TOKEN |
HubSpot |
HUBSPOT_OAUTH_TOKEN |
HubSpot |
APOLLO_IO_API_KEY |
Apollo.io |
APOLLO_IO_SENDER_ID |
Apollo.io |
CLEARBIT_API_KEY |
Clearbit |
STRIPE_API_KEY |
Stripe |
STRIPE_WEBHOOK_SECRET |
Stripe |
STRIPE_ERRORS_PRODUCT_ID |
Stripe |
STRIPE_SESSIONS_PRODUCT_ID |
Stripe |
BASIC_PLAN_PRICE_ID |
Stripe |
ENTERPRISE_PLAN_PRICE_ID |
Stripe |
STARTUP_PLAN_PRICE_ID |
Stripe |
REACT_APP_LD_CLIENT_ID |
LaunchDarkly |
Renamed all Go module paths from the upstream github.com/highlight-run/highlight namespace to the HoldFast repository path.
Changes:
src/backend/go.mod— module declaration changed fromgithub.com/highlight-run/highlight/backendtogithub.com/BrewingCoder/holdfast/src/backendsdk/highlight-go/go.mod— module declaration changed fromgithub.com/highlight/highlight/sdk/highlight-gotogithub.com/BrewingCoder/holdfast/sdk/highlight-gogo.work— workspace updated to reflect new module paths- All Go import statements across
src/backend/updated via find-replace (hundreds of files, mechanical change) go build ./...passes after rename
The core browser SDK (sdk/highlight-run/) was previously published as highlight.run — the upstream Highlight.io package name. It is now published as @holdfast-io/browser under the HoldFast npm org.
Changes:
sdk/highlight-run/package.json—namechanged fromhighlight.runto@holdfast-io/browser- All internal package.json
dependenciesreferencinghighlight.runupdated to@holdfast-io/browser - All internal source imports updated accordingly
Added publish-npm.yml GitHub Actions workflow for publishing SDK packages to npm.
Details:
- Manual dispatch with inputs:
tier(1–4 or all),dry-run,version - Publishes packages in dependency order across 4 tiers (leaf packages first)
- Uses
node -efor version setting to avoid reliance onnpm versionin workspace context - Requires
NPM_TOKENsecret configured in repository settings - Runs on self-hosted runner (
runs-on: [self-hosted, holdfast]) - Builds verified passing for all 4 tiers
All CI/CD workflows (ci-backend.yml, ci-frontend.yml, ci-sdk.yml, security.yml, publish-npm.yml) migrated to a dedicated self-hosted runner.
Configuration:
runs-on: [self-hosted, holdfast]on all workflow jobs- Runner OS: Ubuntu 24.04 VM
- Eliminates GitHub-hosted runner minute consumption and provides consistent build environment
The repository directory structure was reorganized from the upstream flat layout to a cleaner monorepo structure:
| Old Path | New Path |
|---|---|
backend/ |
src/backend/ |
frontend/ |
src/frontend/ |
docker/ |
infra/docker/ |
e2e/ |
tests/e2e/ |
cypress/ |
tests/cypress/ |
scripts/ |
tools/scripts/ |
| (root) | docs/ for all markdown documentation |
The rrweb/ directory was previously tracked as a git submodule pointing to a forked rrweb repository. It is now included as regular files directly in the monorepo.
Why: Submodule checkout requirements (--recurse-submodules) complicated fresh clones and CI setup. Inlining the files removes the dependency on a separate repository and simplifies the clone process.
Effect: git clone https://github.com/BrewingCoder/holdfast is sufficient — no --recurse-submodules flag needed.