Refactor/replace hardcoded urls configurable via env vars#374
Refactor/replace hardcoded urls configurable via env vars#374sekhar08 wants to merge 2 commits intodatabuddy-analytics:mainfrom
Conversation
tracking script in .env.example
|
@sekhar08 is attempting to deploy a commit to the Databuddy OSS Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR replaces hardcoded The approach is sound and the defaults preserve existing behavior for hosted deployments. However, there are a few issues worth addressing before merge:
Confidence Score: 3/5Safe to merge for the hosted product (all defaults are unchanged), but the self-hosting guide has a build-time/runtime confusion for Next.js NEXT_PUBLIC_ vars that will frustrate self-hosters. The code changes themselves are low-risk — simple env var fallbacks with production defaults mean existing deployments are unaffected. The main concern is that the primary deliverable (the self-hosting guide) contains a docker-compose example that won't work as written for NEXT_PUBLIC_* vars, and the NPM snippet generators don't surface the configurable basket URL, which is a silent gap for self-hosters. SELF_HOSTING.md (docker-compose build args for NEXT_PUBLIC_* vars), apps/dashboard/app/(main)/websites/[id]/_components/utils/code-generators.ts (_apiUrl unused in NPM snippets), apps/api/src/index.ts (DASHBOARD_URL trailing slash normalisation) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
ENV["Environment Variables"]
ENV -->|NEXT_PUBLIC_BASKET_URL| DASH_LAYOUT["dashboard/app/layout.tsx\n(self-tracking)"]
ENV -->|NEXT_PUBLIC_BASKET_URL\nNEXT_PUBLIC_TRACKER_URL| CODE_GEN["code-generators.ts\n(install snippet)"]
ENV -->|DASHBOARD_URL| API_CORS["apps/api/src/index.ts\nCORS origins"]
ENV -->|APP_URL| REDIRECT["apps/links/src/routes/redirect.ts\nExpired / Not-found / Proxy URLs"]
ENV -->|LINKS_ROOT_REDIRECT_URL| ROOT["apps/links/src/index.ts\nRoot / redirect"]
ENV -->|GEOIP_DB_URL| GEO_LINKS["apps/links/src/utils/geo.ts\nGeoIP DB fetch"]
ENV -->|GEOIP_DB_URL| GEO_CRON["apps/cron/geo.ts\nGeoIP DB fetch"]
CODE_GEN -->|script src=| TRACKER_SCRIPT["Tracking JS bundle\n(end user browser)"]
CODE_GEN -->|data-api-url=| BASKET_SVC["Basket event service\n(end user browser)"]
DASH_LAYOUT -->|apiUrl=| BASKET_SVC
style ENV fill:#f0f4ff,stroke:#6366f1
style CODE_GEN fill:#fef3c7,stroke:#f59e0b
style DASH_LAYOUT fill:#fef3c7,stroke:#f59e0b
Reviews (1): Last reviewed commit: "feat: add self-hosting environment varia..." | Re-trigger Greptile |
| NODE_ENV: production | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
| clickhouse: | ||
| condition: service_healthy |
There was a problem hiding this comment.
NEXT_PUBLIC_* vars are baked in at Next.js build time, not runtime
In Next.js, any variable prefixed with NEXT_PUBLIC_ is statically inlined into the JavaScript bundle at build time. Setting them under environment: in docker-compose.yml only makes them available to the running container — they will not be picked up by an already-built Next.js app.
As a result, a self-hoster who follows this guide will build the dashboard image, run it with NEXT_PUBLIC_BASKET_URL=https://basket.example.com, and discover that the tracking snippets and the layout tracker still point to basket.databuddy.cc because those values were substituted when the bundle was compiled.
The fix is to pass them as Docker ARGs in the Dockerfile and expose them under build.args: in the Compose file so they are available during next build:
dashboard:
build:
context: .
dockerfile: apps/dashboard/Dockerfile
args:
NEXT_PUBLIC_BASKET_URL: ${NEXT_PUBLIC_BASKET_URL:-https://basket.databuddy.cc}
NEXT_PUBLIC_TRACKER_URL: ${NEXT_PUBLIC_TRACKER_URL:-https://cdn.databuddy.cc/databuddy.js}
environment:
NEXT_PUBLIC_BASKET_URL: ${NEXT_PUBLIC_BASKET_URL:-https://basket.databuddy.cc}
NEXT_PUBLIC_TRACKER_URL: ${NEXT_PUBLIC_TRACKER_URL:-https://cdn.databuddy.cc/databuddy.js}
...The dashboard Dockerfile must also declare matching ARG instructions before the RUN bun run build step. Without this change, NEXT_PUBLIC_BASKET_URL and NEXT_PUBLIC_TRACKER_URL will silently have no effect at runtime.
| ...(process.env.NODE_ENV === "development" | ||
| ? ["http://localhost:3000"] | ||
| : []), | ||
| ...(process.env.DASHBOARD_URL ? [process.env.DASHBOARD_URL] : []), |
There was a problem hiding this comment.
DASHBOARD_URL with trailing slash silently breaks CORS
CORS origin matching is exact — the browser sends the origin as https://app.example.com (no trailing slash), but if a user configures DASHBOARD_URL=https://app.example.com/ (with trailing slash), the string comparison will never match and all cross-origin requests from that dashboard will be blocked with no obvious error message.
Consider stripping a trailing slash when consuming the variable:
| ...(process.env.DASHBOARD_URL ? [process.env.DASHBOARD_URL] : []), | |
| ...(process.env.DASHBOARD_URL ? [process.env.DASHBOARD_URL.replace(/\/$/, "")] : []), |
| const _apiUrl = isLocalhost | ||
| ? "http://localhost:4000" | ||
| : "https://basket.databuddy.cc"; | ||
| : (process.env.NEXT_PUBLIC_BASKET_URL || "https://basket.databuddy.cc"); |
There was a problem hiding this comment.
_apiUrl is computed but never embedded in NPM snippets
_apiUrl is resolved with the new NEXT_PUBLIC_BASKET_URL fallback in generateScriptTag, but its value is never actually used in the returned <script> tag (note the leading _). More importantly, generateNpmCode and generateNpmComponentCode — the functions that produce the NPM/React install snippets — compute no equivalent value, so those snippets always omit the apiUrl prop entirely. A self-hoster whose users copy the NPM snippet will get a <Databuddy> component with no apiUrl, and the SDK will default to basket.databuddy.cc rather than the self-hoster's basket endpoint.
Consider either injecting apiUrl={...} into the NPM snippet when the basket URL differs from the production default, or at minimum documenting that NPM users must add the apiUrl prop manually.
| const APP_URL = process.env.APP_URL || "https://app.databuddy.cc"; | ||
| const EXPIRED_URL = `${APP_URL}/dby/expired`; | ||
| const NOT_FOUND_URL = `${APP_URL}/dby/not-found`; | ||
| const PROXY_URL = `${APP_URL}/dby/l`; |
There was a problem hiding this comment.
Module-level
APP_URL evaluation: env var must be set before first import
APP_URL (and the derived EXPIRED_URL, NOT_FOUND_URL, PROXY_URL) are evaluated once when the module is first imported. This means the APP_URL env var must be present in the process environment before this module is loaded. Any late-binding pattern (e.g., dotenv loaded after imports) will cause the constant to lock in the empty/default value permanently for the lifetime of the process.
This is fine as long as the service's entrypoint loads .env before importing application modules, which is the common pattern. Worth a brief note in the self-hosting docs to ensure APP_URL is set in the process environment rather than relying on a deferred .env load.
|
Hey @izadoesdev, I've added a SELF_HOSTING.md in this PR, should i keep it or remove it? |
Description
Makes all hardcoded production URLs configurable via environment variables to support self-hosting deployments.
Previously, several services contained hardcoded
*.databuddy.ccURLs with no way to override them. Self-hosters would silently have tracking snippets, link redirects, and CORS origins all pointing back to the hosted version. All new env vars default to the current production values, so existing deployments are unaffected.Changes by service:
APP_URLcontrols expired/not-found/proxy redirect destinations;LINKS_ROOT_REDIRECT_URLcontrols root/redirect;GEOIP_DB_URLcontrols GeoLite2 MMDBsource
GEOIP_DB_URLalso applied toapps/cron/geo.tsNEXT_PUBLIC_BASKET_URLcontrols where tracking events are sent;NEXT_PUBLIC_TRACKER_URLcontrols the script URL shown in install snippetsDASHBOARD_URLis added to CORS allowed origins for self-hosted dashboard instancesNew files:
SELF_HOSTING.md— full self-hosting guide with env var reference table, example.env, and a completedocker-compose.yml.env.exampleupdated with all 6 new variablesChecklist
SELF_HOSTING.md,.env.example,apps/dashboard/.env.example)▎ Note on the tests checkbox: no new tests added — these are env var fallbacks with defaults matching the previous hardcoded values, so no behavior changes to test. You can
leave it unchecked or add a note to that effect