Skip to content

Release: staging -> main (privacy controls, insights, AI investigation pipeline)#492

Merged
izadoesdev merged 46 commits into
mainfrom
staging
Jun 26, 2026
Merged

Release: staging -> main (privacy controls, insights, AI investigation pipeline)#492
izadoesdev merged 46 commits into
mainfrom
staging

Conversation

@izadoesdev

@izadoesdev izadoesdev commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Staging -> main release. 18 commits across two themes:

Visitor privacy + tracker (basket/tracker/sdk/validation)

  • Tracker honors visitor privacy controls; error/vitals/outgoing-link plugins gated accordingly
  • Basket trusts gate visitor-ID privacy decisions on IP headers; preserves insertCustomEvents 1-arg call when no auto country; drops defensive request optionality
  • New validation schemas (analytics, custom-events, errors, web-vitals); Node + Vue SDK surface

Dashboard / insights / docs / CI / deps

  • Surface resolved insights; harden onboarding copy action; docs pricing-plan click tracking
  • CI: production env for builds, insights Docker deps, dashboard Playwright browser install
  • Deps: swap tailwind-merge + clsx for cnfast, pin radix-ui

AI investigation pipeline (packages/ai)

  • Cap agent tool-loop at 24 steps (runaway guard)
  • Batch investigation queries per phase to cut round-trips (the fix for the ~180s hang)
  • Keep investigation findings when memo synthesis fails (low-confidence fallback memo instead of discarding agent work)
  • Scope the synthesis catch to generateObject only; cover the fallback wiring with tests

Test plan

  • packages/ai typecheck clean; investigate + wiring tests 20/20
  • Monorepo check-types green (34/34 via pre-commit hook)
  • CI on the PR passes (basket, dashboard, tracker, sdk suites)
  • Smoke-check privacy controls end-to-end on staging deploy before merge

Summary by cubic

Release staging to main with end-to-end visitor ID privacy (“auto” gated by verified client IP), resolved insights with labels/sorting, refreshed goals/settings, and a faster, more reliable investigation pipeline. Also ships safer public/docs error responses with restricted status codes, normalized @databuddy/rpc and OpenAPI output (new monitor/status-page scopes and Uptime routes), redacted logging across services, and a cataloged ingest error schema.

  • New Features

    • API keys/OpenAPI: add read:monitors, write:monitors, read:status_pages, write:status_pages; expose Uptime routes; improve tags/description and show required scopes per operation.
    • Dashboard/docs: preserve register attribution and track signup/onboarding and pricing plan clicks; surface resolved insights with labels and consistent “Newest” sorting.
  • Bug Fixes

    • Errors: mask 5xx details in production, standardize messages (“Authentication required”, “Forbidden”), restrict public error status codes; sanitize public/API/docs/image-proxy responses; normalize oRPC error shapes; downgrade failing health probes to warnings.
    • Ingestion/privacy: trust-gate "auto" visitor-ID decisions using verified client IP; support per-event anonymizeVisitorIds with tracker-level precedence; return sanitized per-item schema errors; catalog stable error codes.
    • Access/scopes: enforce new monitor/status-page scopes in schedule and resource checks; expose @databuddy/auth/permissions subpath and fix export init race.
    • Logging: apply databuddyEvlogRedaction and typed wide-event fields across services.
    • AI pipeline: cap tool-loop at 24 steps, batch queries per phase to cut round-trips, and fall back to a low-confidence memo if synthesis fails.

Written for commit 261fab5. Summary will update on new commits.

Review in cubic

- Replace `cn` implementation in packages/ui, apps/dashboard, apps/docs
  with a re-export from cnfast (drop-in, byte-identical output).
- Drop tailwind-merge from all three workspaces and the catalog. Drop
  clsx from packages/ui and apps/docs (apps/dashboard still imports it
  directly).
- Pin apps/dashboard `radix-ui` from `latest` to `^1.4.3` (matches the
  apps/docs pin and currently resolved version). The `latest` sentinel
  was a re-resolve time bomb: any `bun install` pulled radix-ui@1.6.0
  and cascade-bumped every @radix-ui/* transitive, which introduced a
  `--radix-${string}` CSS index signature that breaks @hello-pangea/dnd
  typing in edit-funnel-dialog.tsx.
Addresses cubic review findings on PR #491.

- Visitor country for "auto" anonymization now derives from
  extractTrustedClientIp(request) (gated on IP_HEADER_VERIFIED), not the
  raw extractIpFromRequest result. Forged client IP headers could
  previously flip auto-mode events out of anonymization and store raw
  visitor IDs. Default-safe: missing trusted IP -> undefined country ->
  shouldAnonymizeVisitorIds returns true. (P1)
- Extracts getVisitorCountryForAutoMode into @utils/ip-geo so basket
  and track routes share one implementation. Removes the duplicate
  inline path in track.ts and the redundant insertCustomEvents
  branching. (P3)
- Applies the same trusted-country gate to processTrackEventData,
  insertTrackEvent, insertOutgoingLink, and the batch route's
  getBatchVisitorCountry closure (same root cause, same file).
- Tracker errors.ts: move anonymizeVisitorIds after the ...error
  spread so an error payload carrying that key cannot silently
  overwrite tracker-level privacy config. (P2)
- Add anonymizeVisitorIds to the legacy webVitalsEventSchema payload
  so v1-format clients no longer silently drop the flag. (P2)
- Make anonymizeVisitorIds .nullable().optional() and transform null
  -> undefined at the schema boundary across analytics, errors,
  web-vitals, and custom-events. Matches every other optional field
  and keeps downstream types as boolean | "auto" | undefined. (P3)
- Rewrite the "ignores object-not-found rejection noise" test as a
  deterministic noise+sentinel assertion (was a 250ms waitForTimeout
  + assert false, racy). (P2)
Follow-up to 3716b58. The integration test suite asserts
insertCustomEvents is called with a single events arg when no event
opted into auto-mode anonymization. Restoring the existing
`if (visitorCountry === undefined)` branch in both routes keeps the
call signature compatible, and adds the new getVisitorCountryForAutoMode
export to the @utils/ip-geo mock so 18 vitest cases that previously
crashed with `undefined is not a function` pass again.
…anching

Desloppify pass on the trust-gate changes from 3716b58 / f8ca22e.

- insertTrackEvent, insertOutgoingLink, processTrackEventData all take
  request: Request now. The parameter was already passed by every
  caller; the `?` was defensive sloppy typing, and forced `request &&`
  guards before extractTrustedClientIp(request) at three call sites.
- Drop the `if (visitorCountry === undefined)` branch in basket.ts
  and track.ts. insertCustomEvents(events, undefined) is identical to
  insertCustomEvents(events); the conditional was over-specified test
  surface, not behavior. Updates the 6 integration assertions to call
  toHaveBeenCalledWith([...], undefined).
- insertOutgoingLink: extractTrustedClientIp already returns null when
  IP_HEADER_VERIFIED is false, so the `request ? ... : null` ternary
  was redundant.
- security.ts: applyVisitorIdPrivacy now throws when salt is undefined
  but anonymizeVisitorIds is true. The previous `salt ?? ""` fallback
  silently produced a deterministic, day-invariant hash that defeated
  daily salt rotation. All current callers fetch the salt before
  calling, so this is a future-regression guard.
- event-service.ts: drop unused ip param from insertOutgoingLink; it
  now derives the trusted IP from request via extractTrustedClientIp,
  matching insertTrackEvent.
- basket.ts: drop ip from /vitals, /errors, /events validateRequest
  destructuring (no longer used after the getVisitorCountryForAutoMode
  refactor); update insertOutgoingLink call sites for the dropped param.
- cockpit-signals.tsx: client-side "Newest" sort now uses
  resolvedAt ?? createdAt, matching the server's
  COALESCE(resolvedAt, createdAt) default sort. Without this, picking
  "Newest" reordered resolved insights vs the default load order.
- Format: long imports auto-wrapped by biome.
…cy-cleanup-staging

Fix insights scan issues and resolution UI
Replace NEVER_STOP with a stepCountIs(24) ceiling so agent runs converge
before per-step latency exhausts the wall-clock budget.
Each phase of the investigation brief now fans out its independent
queries in a single turn instead of one tool call per step. Halves
agent steps (15 to 7) and brings wall time inside the budget.
A synthesis timeout or invalid object previously threw away the entire
agent run. Fall back to a low-confidence memo built from the agent's
findings so the expensive investigation isn't lost.
…iring

Narrow the try/catch around generateObject so render and receipt errors
propagate instead of being mislabeled as synthesis failures. Add a wiring
test that drives runInvestigation through both the success and synthesis-throw
paths.
@vercel

vercel Bot commented Jun 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard (staging) Ready Ready Preview, Comment Jun 25, 2026 1:49pm
databuddy-status Ready Ready Preview, Comment Jun 25, 2026 1:49pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
documentation (staging) Skipped Skipped Jun 25, 2026 1:49pm

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d4b2a972-a4c8-48cb-9e94-eb9847db82dd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staging

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@unkey-deploy

unkey-deploy Bot commented Jun 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Unkey Deploy

Name Status Preview Inspect Updated (UTC)
api (preview) Ready Visit Preview Inspect Jun 25, 2026 3:25pm
api (production) Ready Visit Preview Inspect Jun 26, 2026 6:36am

@socket-security

socket-security Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcnfast@​0.0.6811009891100

View full report

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 55 files

Confidence score: 4/5

  • In packages/rpc/src/routers/insights.ts, switching history sorting to coalesce(resolved_at, created_at) without a matching index can cause slower queries as org data grows, which could show up as higher latency in insights/history endpoints after release — add an expression index (or a persisted sortable column) before merging to de-risk regression.
  • In apps/docs/app/(home)/pricing/_pricing/estimator.tsx, the new CTA tracking helper now diverges from existing pricing tracking logic, which can lead to inconsistent analytics payloads between estimator and table placements and noisier reporting — extract a shared helper that accepts placement and reuse it in both components before merge (or immediately after as a follow-up).
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/rpc/src/routers/insights.ts">

<violation number="1" location="packages/rpc/src/routers/insights.ts:546">
P2: History query switched to expression-based ORDER BY without a matching index, which can regress latency on large orgs. Add an expression index (or equivalent sortable column) for `coalesce(resolved_at, created_at)` scoped by org/website filters.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Tracker as Browser Tracker
    participant NodeSDK as Node/Vue SDK
    participant Basket as Basket API
    participant Security as Security Module
    participant Geo as IP Geo Utils
    participant DB as ClickHouse
    participant AI as AI Investigation
    participant Dashboard as Dashboard UI
    participant Docs as Docs Site

    Note over Tracker,Docs: Visitor Privacy Controls

    Tracker->>Tracker: emit event with anonymizeVisitorIds setting
    Tracker->>Basket: POST /track, /errors, /web-vitals, /outgoing_link
    Note over Basket: extract request from payload
    
    Basket->>Geo: extractTrustedClientIp(request)
    Geo-->>Basket: trusted IP or null
    
    alt Trusted IP present
        Basket->>Geo: getGeo(trustedIp, request)
        Geo-->>Basket: geoData (country)
    end
    
    Basket->>Security: shouldAnonymizeVisitorIds(setting, country)
    Security-->>Basket: boolean decision
    
    alt anonymizeVisitorIds = true or "auto" with non-US country
        Basket->>Security: getDailySalt()
        Security-->>Basket: daily salt
        Basket->>Security: applyVisitorIdPrivacy(rawId, true, salt)
        Security-->>Basket: salted/hashed ID
    else anonymizeVisitorIds = false or "auto" with US country
        Basket->>Security: applyVisitorIdPrivacy(rawId, false)
        Security-->>Basket: raw ID unchanged
    end
    
    Basket->>DB: insert event with processed ID

    Note over Tracker,Docs: Error & Vitals Filtering

    Tracker->>Tracker: onerror / onunhandledrejection handler
    Tracker->>Tracker: filter browser runtime noise patterns
    Tracker->>Tracker: filter extension source errors
    Tracker->>Basket: POST with filtered errors + anonymizeVisitorIds

    Note over AI: Investigation Pipeline

    AI->>AI: runInvestigation()
    AI->>AI: build phase-batched queries
    loop per phase (max 24 steps)
        AI->>AI: batch all independent queries in 1 turn
        AI->>AI: emit parallel tool calls
    end
    AI->>AI: generateObject() for memo synthesis
    alt synthesis succeeds
        AI-->>AI: structured memo
    else synthesis fails
        AI->>AI: buildFallbackMemo(answer)
        AI-->>AI: low-confidence fallback memo
    end
    AI-->>Dashboard: investigation result

    Note over Dashboard: Insights & Resolution

    Dashboard->>DB: query insights with COALESCE(resolvedAt, createdAt) sort
    DB-->>Dashboard: insights including status, resolvedAt, resolvedReason
    Dashboard->>Dashboard: render status labels (Recovered/Archived)
    Dashboard->>Dashboard: filter resolved insights count

    Note over Docs: Pricing Click Tracking

    Docs->>NodeSDK: track("pricing_plan_clicked", {plan, placement})
    NodeSDK->>Basket: POST /track with anonymizeVisitorIds config
Loading

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread packages/rpc/src/routers/insights.ts
Comment thread apps/docs/app/(home)/pricing/_pricing/estimator.tsx Outdated
…n tests

Ultracite-format stop-conditions.ts and investigate.ts to satisfy CI lint.
Spread the real `ai` and `run-agent` modules in the wiring test instead of
replacing them wholesale, which dropped the `createGateway` export and crashed
the package test suite at load. Restore both modules in afterAll to contain the
mock within this file.
Extract trackPricingPlanClick(planId, placement) so the comparison table and
estimator emit identical pricing_plan_clicked payloads, removing the duplicate
inline trackers that could drift. Addresses cubic P3 on PR #492.
…d_at)

The history query orders by coalesce(resolved_at, created_at) desc but every
existing index sorts on created_at, so large orgs fall back to a sort. Add
org- and website-scoped expression indexes matching the query. Addresses
cubic P2 on PR #492.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 17 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/src/routes/health.ts">

<violation number="1" location="apps/api/src/routes/health.ts:22">
P2: Unthrottled error-level logging in health check probe failures can generate log storms during outages. Health endpoints are polled frequently by load balancers and orchestrators; without throttling, sampling, or deduplication, every failed probe emits an error log, creating high-volume repetitive noise that increases log costs and obscures actionable signals.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/shared/src/http-error-response.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@unkey-deploy unkey-deploy Bot temporarily deployed to api - production June 26, 2026 06:34 Inactive
@unkey-deploy unkey-deploy Bot temporarily deployed to api - production June 26, 2026 06:36 Inactive
@unkey-deploy unkey-deploy Bot temporarily deployed to api - production June 26, 2026 06:36 Inactive
@izadoesdev izadoesdev merged commit 177f068 into main Jun 26, 2026
22 checks passed
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.

2 participants