Skip to content

clickhouse setup#1032

Merged
N2D4 merged 43 commits intodevfrom
clickhouse-setup
Jan 28, 2026
Merged

clickhouse setup#1032
N2D4 merged 43 commits intodevfrom
clickhouse-setup

Conversation

@BilalG1
Copy link
Copy Markdown
Collaborator

@BilalG1 BilalG1 commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • ClickHouse analytics backend: store/query events, admin analytics query API (includes CPU and wall-clock timings) and migration/backfill endpoints.
  • Dashboard

    • Interactive ClickHouse SQL editor and a migration UI with progress, controls, and batch management.
  • Infrastructure

    • Local/CI ClickHouse service, environment configuration, and run scripts integrated into compose/CI.
  • Tests

    • New end-to-end tests for analytics queries/events; snapshot redactions for timing values.
  • Docs / Errors

    • New user-facing analytics error types for timeouts and query failures.

✏️ Tip: You can customize this high-level summary in your review settings.


Note

Add ClickHouse-backed analytics: readonly query API with timing, dual-write event storage and migration, dashboard query editor/migration UI, and local/CI setup.

  • Backend (Analytics + ClickHouse):
    • ClickHouse integration: New @/lib/clickhouse client, env vars, and migrations creating analytics.events; row policy and restricted limited_user grants.
    • Event ingestion: Dual-write backend events to analytics.events (src/lib/events.tsx).
    • Query API: New admin endpoint POST /api/v1/internal/analytics/query executing readonly, tenant-scoped ClickHouse queries and returning results + CPU/wall times; adds KnownErrors for analytics.
    • Migration API: Internal endpoint to backfill events from Postgres to ClickHouse with cursor/limits; wired into DB migration script.
  • Dashboard:
    • Analytics Query UI: Page with ClickHouse SQL editor (Monaco, autocomplete) and JSON results.
    • ClickHouse Migration UI: Internal page to run batched backfills with progress/cursor.
  • Shared/SDK:
    • Admin interface additions (queryAnalytics, ClickHouse migration) and analytics types.
  • DevOps:
    • Docker Compose/CI add ClickHouse services; .env examples and clickhouse scripts; Dev Launchpad entries.
  • Tests:
    • E2E coverage for analytics query behavior, permissions/limits, event visibility; snapshot serializer redacts timing fields.

Written by Cursor Bugbot for commit 1134883. This will update automatically on new commits. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Nov 26, 2025

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

Project Deployment Review Updated (UTC)
stack-backend Ready Ready Preview, Comment Jan 28, 2026 5:16pm
stack-dashboard Ready Ready Preview, Comment Jan 28, 2026 5:16pm
stack-demo Ready Ready Preview, Comment Jan 28, 2026 5:16pm
stack-docs Ready Ready Preview, Comment Jan 28, 2026 5:16pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 26, 2025

📝 Walkthrough

Walkthrough

Adds ClickHouse integration: infra and CI updates, client library and utilities, migrations, dual-write event logging, admin analytics query and backfill APIs, dashboard query/migration UIs, types/interfaces, E2E tests, and two analytics-specific KnownErrors.

Changes

Cohort / File(s) Summary
Infra & Env
apps/backend/.env, apps/backend/.env.development, docker/server/.env.example, docker/dependencies/docker.compose.yaml, .github/workflows/docker-server-build-run.yaml, apps/dev-launchpad/public/index.html, package.json, apps/backend/package.json
Add ClickHouse env vars, Docker Compose service & volume, CI step to start ClickHouse, dev-launchpad UI entries, and root/backend clickhouse run scripts.
Backend scripts & migrations
apps/backend/scripts/clickhouse-migrations.ts, apps/backend/scripts/db-migrations.ts
New ClickHouse migration script (DB/table/view/user/policies) and integration into existing DB migrate/drop flows.
ClickHouse client & utils
apps/backend/src/lib/clickhouse.tsx
New client factory, admin/external clients, config flag, and getQueryTimingStats (flush logs + read system.query_log).
Event dual-write & tokens
apps/backend/src/lib/events.tsx, apps/backend/src/lib/tokens.tsx
Conditional ClickHouse dual-write of events and inclusion of teamId in event logging payload.
Analytics query API
apps/backend/src/app/api/latest/internal/analytics/query/route.ts
New admin-only POST route executing scoped ClickHouse queries with params, timeouts, limits, timing stats and error mapping.
ClickHouse migrations API
apps/backend/src/app/api/latest/internal/clickhouse/migrate-events/route.tsx
New internal POST route to backfill Postgres events into ClickHouse with cursor paging, idempotency, progress and stats.
Dashboard — Query UI
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/query-analytics/*, apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/query-analytics/page.tsx
New Monaco-based ClickHouse SQL editor, language definition, autocomplete, run shortcut, adminApp.queryAnalytics integration and results pane.
Dashboard — Migration UI
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/clickhouse-migration/*, apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/clickhouse-migration/page.tsx
New migration UI/page to run batched migrations with start/stop/reset, cursor handling, progress and stats.
Types & Admin interface
packages/stack-shared/src/interface/crud/analytics.ts, packages/stack-shared/src/interface/admin-interface.ts, packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts, packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
Add AnalyticsQuery* and ClickhouseMigration* types and admin methods queryAnalytics and migrateEventsToClickhouse with pass-through impl.
KnownErrors & tests infra
packages/stack-shared/src/known-errors.tsx, apps/e2e/tests/snapshot-serializer.ts, apps/e2e/tests/backend/backend-helpers.ts
Add AnalyticsQueryTimeout and AnalyticsQueryError; snapshot redaction for timing and stricter camelCase regex for tests.
E2E tests
apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts, apps/e2e/tests/backend/endpoints/api/v1/analytics-events.test.ts, apps/e2e/tests/*
New comprehensive tests for analytics query endpoint and ClickHouse-backed event storage/access controls, with retry and snapshot helpers.
Scripts & package metadata
apps/backend/package.json, package.json
Add @clickhouse/client dependency and clickhouse run scripts (backend + root).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Dashboard as "Dashboard (React)"
    participant Backend as "Backend API"
    participant ClickHouse as "ClickHouse"
    participant QueryLog as "system.query_log"

    User->>Dashboard: Run SQL query (query, params, timeout_ms)
    Dashboard->>Backend: POST /internal/analytics/query
    Backend->>Backend: Authenticate (admin), generate query_id
    Backend->>ClickHouse: Execute parameterized query (scoped settings, limits)
    ClickHouse-->>Backend: JSON result rows
    Backend->>ClickHouse: SYSTEM FLUSH LOGS
    Backend->>QueryLog: SELECT cpu_time_ms, wall_clock_time_ms WHERE query_id=...
    QueryLog-->>Backend: timing stats
    Backend-->>Dashboard: { result, timing }
    Dashboard->>User: Display results + timing
Loading
sequenceDiagram
    actor User
    participant Dashboard as "Migration UI"
    participant Backend as "Backend API"
    participant Postgres as "Postgres"
    participant ClickHouse as "ClickHouse"

    User->>Dashboard: Start migration (min,max,cursor,limit)
    loop per batch
        Dashboard->>Backend: POST /internal/clickhouse/migrate-events
        Backend->>Postgres: SELECT events WHERE created_at BETWEEN range ORDER BY created_at,id LIMIT N
        Postgres-->>Backend: rows
        Backend->>Backend: Transform rows → ClickHouse JSONEachRow
        Backend->>ClickHouse: INSERT INTO analytics_internal.events (JSONEachRow, async_insert)
        ClickHouse-->>Backend: insert ack
        Backend-->>Dashboard: { processed_events, inserted_rows, progress, next_cursor }
        Dashboard->>User: Update progress
    end
    Dashboard->>User: Migration complete
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • N2D4

Poem

🐇
I hopped to the logs with whiskers bright,
ClickHouse sipped events through the night.
Rows in JSON hopped in tidy rows,
Dashboards blinked as insight grows.
Nibble, count, report — analytics glows!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'clickhouse setup' is vague and generic, failing to clearly convey the main scope of this comprehensive analytics implementation across multiple systems. Consider a more descriptive title such as 'Add ClickHouse-backed analytics with query API, event ingestion, and dashboard UI' to better communicate the breadth and purpose of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is well-documented with a detailed Cursor summary covering backend analytics, dashboard, shared/SDK, DevOps, and tests components, despite using the minimal template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Nov 26, 2025

Greptile Overview

Greptile Summary

This PR establishes the foundational ClickHouse integration for analytics, adding database infrastructure, client library, API endpoint, and comprehensive security controls.

Major Changes:

  • Added ClickHouse service to Docker Compose with proper volume management and port configuration
  • Implemented two-tier authentication system: admin user for migrations/system operations and limited_user for query execution with restricted permissions
  • Created /api/latest/analytics/query endpoint with SmartRouteHandler that enforces server-level auth, parameterized queries, configurable timeouts, and tenancy isolation
  • Added migration script that creates limited_user with SELECT-only permissions (references non-existent allowed_table1)
  • Implemented query timing stats retrieval using admin privilege escalation to access system.query_log
  • Added comprehensive E2E tests covering security boundaries (no CREATE, INSERT, or system table access)

Issues Found:

  • Migration grants SELECT on non-existent analytics.allowed_table1, which will cause migration failure
  • Missing fallback handling in getQueryTimingStats when query doesn't appear in query_log (will throw runtime error accessing undefined)

Confidence Score: 2/5

  • This PR has critical issues that will cause migration failures in production
  • Score reflects two critical bugs: the migration references a non-existent table which will fail on execution, and missing error handling in stats retrieval that will cause runtime crashes. The security model and API design are solid, but the implementation has blocking issues.
  • Pay close attention to apps/backend/scripts/clickhouse-migrations.ts (references non-existent table) and apps/backend/src/lib/clickhouse.tsx (missing error handling)

Important Files Changed

File Analysis

Filename Score Overview
apps/backend/scripts/clickhouse-migrations.ts 2/5 Added ClickHouse migration script with user creation and permissions, but references non-existent table
apps/backend/src/lib/clickhouse.tsx 3/5 Implemented ClickHouse client factory and query timing stats retrieval with admin escalation
apps/backend/src/app/api/latest/analytics/query/route.tsx 4/5 Added analytics query endpoint with proper auth, timeout handling, and error management

Sequence Diagram

sequenceDiagram
    participant Client
    participant AnalyticsAPI
    participant ClickHouse
    participant AdminConnection

    Client->>AnalyticsAPI: POST analytics query
    AnalyticsAPI->>ClickHouse: Execute with limited user
    
    alt Success
        ClickHouse-->>AnalyticsAPI: Result data
        AnalyticsAPI->>AdminConnection: Get timing stats
        AdminConnection-->>AnalyticsAPI: Stats
        AnalyticsAPI-->>Client: Result with stats
    else Timeout or Error
        ClickHouse-->>AnalyticsAPI: Error
        AnalyticsAPI-->>Client: Error response
    end
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

11 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment thread apps/backend/scripts/clickhouse-migrations.ts Outdated
Comment thread apps/backend/src/lib/clickhouse.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
apps/backend/scripts/clickhouse-migrations.ts (1)

9-12: Using plaintext password authentication.

While plaintext_password is acceptable for development environments, consider documenting this choice or using sha256_password for better security practices.

Example with SHA256:

import { createHash } from 'crypto';

const passwordHash = createHash('sha256')
  .update(clickhouseExternalPassword)
  .digest('hex');

await client.exec({
  query: "CREATE USER IF NOT EXISTS limited_user IDENTIFIED WITH sha256_password BY {passwordHash:String}",
  query_params: { passwordHash },
});
apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (2)

1-29: Good test coverage for basic query execution.

The tests appropriately use inline snapshots as per coding guidelines. Consider adding a negative test case verifying that client accessType is rejected, since the route requires serverOrHigherAuthTypeSchema.


274-387: Security tests are comprehensive.

Good coverage of dangerous operations (CREATE TABLE, system tables, KILL QUERY, INSERT). Note that error messages expose the internal username limited_user - consider whether this level of detail should be sanitized in the route handler before returning to clients.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cb8806 and 0c08896.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/backend/.env.development (1 hunks)
  • apps/backend/package.json (1 hunks)
  • apps/backend/scripts/clickhouse-migrations.ts (1 hunks)
  • apps/backend/scripts/db-migrations.ts (2 hunks)
  • apps/backend/src/app/api/latest/analytics/query/route.tsx (1 hunks)
  • apps/backend/src/lib/clickhouse.tsx (1 hunks)
  • apps/dev-launchpad/public/index.html (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (1 hunks)
  • apps/e2e/tests/snapshot-serializer.ts (1 hunks)
  • docker/dependencies/docker.compose.yaml (2 hunks)
  • packages/stack-shared/src/known-errors.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Ensure code passes pnpm typecheck for TypeScript type validation
Never use toast for blocking alerts and errors; use alerts instead as they are more visible to users
Keep hover/click transitions snappy and fast; apply transitions after the action (e.g., smooth fade-out on hover end) rather than delaying actions with pre-transitions to avoid sluggish UI
Never use try-catch-all, never void a promise, never use .catch(console.error) or similar; use runAsynchronously or runAsynchronouslyWithAlert for error handling instead of try-catch blocks
Use loading indicators instead of try-catch blocks for asynchronous UI operations; button components like support async callbacks with built-in loading state
Use ES6 maps instead of records wherever possible

Files:

  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/e2e/tests/snapshot-serializer.ts
  • apps/backend/src/app/api/latest/analytics/query/route.tsx
  • apps/backend/src/lib/clickhouse.tsx
  • packages/stack-shared/src/known-errors.tsx
  • apps/backend/scripts/db-migrations.ts
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer client components and dynamic functions like usePathname over Next.js dynamic functions to keep pages static; avoid using await params or similar dynamic patterns

Files:

  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/e2e/tests/snapshot-serializer.ts
  • apps/backend/src/app/api/latest/analytics/query/route.tsx
  • apps/backend/src/lib/clickhouse.tsx
  • apps/backend/scripts/db-migrations.ts
apps/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Always add new E2E tests when you change the API or SDK interface

Files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/e2e/tests/snapshot-serializer.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{ts,tsx}: Run all tests using pnpm test run; run specific tests using pnpm test run <file-filters> with Vitest
Use .toMatchInlineSnapshot for test assertions instead of other selectors when possible; check snapshot-serializer.ts for formatting and non-deterministic value handling

Files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
apps/backend/src/app/api/latest/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

In the Stack Auth monorepo backend API, organize routes by resource type (auth, user management, team management, OAuth providers) in /apps/backend/src/app/api/latest/*

Files:

  • apps/backend/src/app/api/latest/analytics/query/route.tsx
🧠 Learnings (4)
📚 Learning: 2025-11-25T02:09:03.104Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: Applies to packages/stack-shared/src/config/** : When making backwards-incompatible changes to the config schema, update the migration functions in `packages/stack-shared/src/config/schema.ts`

Applied to files:

  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/scripts/db-migrations.ts
📚 Learning: 2025-11-25T02:09:03.104Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: Applies to apps/e2e/**/*.{ts,tsx} : Always add new E2E tests when you change the API or SDK interface

Applied to files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
📚 Learning: 2025-11-25T02:09:03.104Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use `.toMatchInlineSnapshot` for test assertions instead of other selectors when possible; check snapshot-serializer.ts for formatting and non-deterministic value handling

Applied to files:

  • apps/e2e/tests/snapshot-serializer.ts
📚 Learning: 2025-11-25T02:09:03.104Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: Applies to apps/backend/src/app/api/latest/**/*.{ts,tsx} : In the Stack Auth monorepo backend API, organize routes by resource type (auth, user management, team management, OAuth providers) in `/apps/backend/src/app/api/latest/*`

Applied to files:

  • apps/backend/src/app/api/latest/analytics/query/route.tsx
🧬 Code graph analysis (3)
apps/backend/scripts/clickhouse-migrations.ts (2)
apps/backend/src/lib/clickhouse.tsx (1)
  • createClickhouseClient (11-19)
packages/stack-shared/src/utils/env.tsx (1)
  • getEnvVariable (16-58)
packages/stack-shared/src/known-errors.tsx (2)
packages/stack-shared/src/index.ts (1)
  • KnownError (14-14)
packages/stack-shared/src/utils/results.tsx (1)
  • error (36-41)
apps/backend/scripts/db-migrations.ts (1)
apps/backend/scripts/clickhouse-migrations.ts (1)
  • runClickhouseMigrations (4-24)
🪛 dotenv-linter (4.0.0)
apps/backend/.env.development

[warning] 75-75: [SubstitutionKey] The CLICKHOUSE_URL key is not assigned properly

(SubstitutionKey)


[warning] 76-76: [UnorderedKey] The CLICKHOUSE_ADMIN_USER key should go before the CLICKHOUSE_URL key

(UnorderedKey)


[warning] 77-77: [UnorderedKey] The CLICKHOUSE_ADMIN_PASSWORD key should go before the CLICKHOUSE_ADMIN_USER key

(UnorderedKey)


[warning] 78-78: [UnorderedKey] The CLICKHOUSE_EXTERNAL_USER key should go before the CLICKHOUSE_URL key

(UnorderedKey)


[warning] 79-79: [UnorderedKey] The CLICKHOUSE_EXTERNAL_PASSWORD key should go before the CLICKHOUSE_EXTERNAL_USER key

(UnorderedKey)


[warning] 80-80: [UnorderedKey] The CLICKHOUSE_DATABASE key should go before the CLICKHOUSE_EXTERNAL_PASSWORD key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Vercel Agent Review
🔇 Additional comments (12)
apps/e2e/tests/snapshot-serializer.ts (1)

71-72: LGTM!

Adding timing fields to stripFields is appropriate for test stability, as these values are non-deterministic and would cause snapshot tests to fail.

apps/backend/.env.development (1)

73-80: LGTM!

The ClickHouse environment variables follow the established patterns in this file. The port interpolation and password placeholder conventions are consistent with other services.

Note: The static analysis warnings about SubstitutionKey and UnorderedKey can be safely ignored—these are false positives given the standard patterns used throughout this .env file.

apps/dev-launchpad/public/index.html (2)

132-132: LGTM!

The ClickHouse background service entry is consistent with other services and correctly uses port suffix 33.


304-312: LGTM!

The ClickHouse app tile follows the established pattern and correctly references port suffix 33, matching the Docker service configuration.

apps/backend/scripts/db-migrations.ts (2)

11-11: LGTM!

The import is correctly structured.


155-156: LGTM!

Running ClickHouse migrations after Prisma migrations complete is the correct sequencing. The async/await usage is proper.

apps/backend/src/lib/clickhouse.tsx (1)

11-19: LGTM!

The client factory function correctly handles both admin and external authentication modes with optional timeout configuration.

docker/dependencies/docker.compose.yaml (1)

225-241: ClickHouse 25.10 is a stable release (verified Oct 31, 2025), and a patch update (25.10.1) is also available.

The image version specified in the docker-compose configuration is current, well-supported, and appropriate for use. No concerns with the version choice or service configuration.

apps/backend/package.json (1)

46-46: @clickhouse/client version 1.14.0 is current and has no known security vulnerabilities.

Version 1.14.0 is the latest stable release (released November 20, 2025), and the ^1.14.0 specifier is appropriate. No known security vulnerabilities were identified for the @clickhouse/client npm package.

apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (1)

217-244: LGTM!

The timeout test using SELECT sleep(3) with a 100ms timeout is a reliable way to verify timeout handling.

packages/stack-shared/src/known-errors.tsx (2)

1632-1652: LGTM!

The new AnalyticsQueryTimeout and AnalyticsQueryError constructors follow the established pattern for known errors. The HTTP 400 status is appropriate, and the constructorArgsFromJson implementations correctly deserialize the error details.


1784-1785: LGTM!

The new error types are properly exported in the KnownErrors object.

Comment thread apps/backend/scripts/clickhouse-migrations.ts
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/src/lib/clickhouse.tsx
Comment thread apps/backend/src/lib/clickhouse.tsx
Comment thread apps/backend/src/app/api/latest/analytics/query/route.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/backend/scripts/clickhouse-migrations.ts (1)

4-23: Migration GRANT targets a likely non-existent table and hardcodes the external user

This script still has the two issues called out in earlier reviews:

  • GRANT SELECT ON analytics.allowed_table1 TO limited_user; will fail if analytics.allowed_table1 doesn’t exist yet (which seems likely given the TODO about creating migration files).
  • The external user name is hardcoded as limited_user, even though STACK_CLICKHOUSE_EXTERNAL_USER exists and is used elsewhere; that can drift.

You could make this more robust along these lines:

 export async function runClickhouseMigrations() {
   console.log("Running Clickhouse migrations...");
   const client = createClickhouseClient("admin");
-  const clickhouseExternalPassword = getEnvVariable("STACK_CLICKHOUSE_EXTERNAL_PASSWORD");
-  // todo: create migration files
-  await client.exec({
-    query: "CREATE USER IF NOT EXISTS limited_user IDENTIFIED WITH plaintext_password BY {clickhouseExternalPassword:String}",
-    query_params: { clickhouseExternalPassword },
-  });
-  const queries = [
-    "GRANT SELECT ON analytics.allowed_table1 TO limited_user;",
-    "REVOKE ALL ON system.* FROM limited_user;",
-    "REVOKE CREATE, ALTER, DROP, INSERT ON *.* FROM limited_user;"
-  ];
-  for (const query of queries) {
-    console.log(query);
-    await client.exec({ query });
-  }
-  console.log("Clickhouse migrations complete");
-  await client.close();
+  const externalUser = getEnvVariable("STACK_CLICKHOUSE_EXTERNAL_USER", "limited_user");
+  const clickhouseExternalPassword = getEnvVariable("STACK_CLICKHOUSE_EXTERNAL_PASSWORD");
+
+  try {
+    // TODO: create proper ClickHouse schema migrations
+    await client.exec({
+      query: "CREATE USER IF NOT EXISTS {externalUser:Identifier} IDENTIFIED WITH plaintext_password BY {clickhouseExternalPassword:String}",
+      query_params: { externalUser, clickhouseExternalPassword },
+    });
+
+    const queries = [
+      // Enable GRANTs once the target tables exist.
+      // "GRANT SELECT ON analytics.some_table TO {externalUser:Identifier};",
+      `REVOKE ALL ON system.* FROM ${externalUser};`,
+      `REVOKE CREATE, ALTER, DROP, INSERT ON *.* FROM ${externalUser};`,
+    ];
+
+    for (const query of queries) {
+      console.log(query);
+      await client.exec({ query });
+    }
+
+    console.log("Clickhouse migrations complete");
+  } finally {
+    await client.close();
+  }
 }

Adjust the GRANT line once your analytics tables are in place.

apps/backend/src/lib/clickhouse.tsx (1)

22-55: Fix getQueryTimingStats typing and guard against missing query_log rows

This function still has the issues called out in earlier reviews:

  • profile.json is typed as if it returns a flat { cpu_time_ms, wall_clock_time_ms }, but you then access stats.data[0]; this doesn’t match the ClickHouse JSON shape and will likely fail type-checking.
  • At runtime, system.query_log can legitimately return an empty data array (log entry not flushed yet), making stats.data[0] undefined and crashing callers that assume stats are always present.

A safer version would be:

-export const getQueryTimingStats = async (client: ClickHouseClient, queryId: string) => {
+export const getQueryTimingStats = async (
+  client: ClickHouseClient,
+  queryId: string,
+): Promise<{ cpu_time_ms: number; wall_clock_time_ms: number }> => {
@@
-  const stats = await profile.json<{
-    cpu_time_ms: number,
-    wall_clock_time_ms: number,
-  }>();
-  return stats.data[0];
+  const stats = await profile.json<{
+    data: Array<{
+      cpu_time_ms: number;
+      wall_clock_time_ms: number;
+    }>;
+  }>();
+
+  if (!stats.data || stats.data.length === 0) {
+    throw new Error(
+      `Query timing stats not found for query_id=${queryId}; query_log entry may not be available yet.`,
+    );
+  }
+
+  return stats.data[0];
 };

Callers can then convert this error into a KnownErrors.AnalyticsQueryError or similar, as appropriate for the API surface.

🧹 Nitpick comments (2)
.github/workflows/docker-server-test.yaml (1)

26-30: Consider adding a lightweight readiness check for ClickHouse

The container may not always be ready within 5 seconds, especially on a busy CI runner. A transient slow start would make this job flaky.

Consider replacing the fixed sleep with a small readiness loop, for example:

      - name: Setup clickhouse
        run: |
          docker run -d --name clickhouse \
            -e CLICKHOUSE_DB=analytics \
            -e CLICKHOUSE_USER=stackframe \
            -e CLICKHOUSE_PASSWORD=password \
            -p 8133:8123 clickhouse/clickhouse-server:25.10

          for i in {1..30}; do
            if docker exec clickhouse clickhouse-client --query "SELECT 1" >/dev/null 2>&1; then
              echo "ClickHouse is ready"
              break
            fi
            echo "Waiting for ClickHouse..."
            sleep 1
          done

          docker logs clickhouse

</blockquote></details>
<details>
<summary>apps/backend/.env.development (1)</summary><blockquote>

`74-80`: **ClickHouse env block looks consistent with backend usage**

The new `STACK_CLICKHOUSE_*` variables line up with `createClickhouseClient` and the CI ClickHouse setup (DB `analytics`, admin user `stackframe`, external user `limited_user`), so this should wire up cleanly for local dev.

The `dotenv-linter` warnings here (substitution and key ordering) are stylistic only; the same `${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}` pattern is already used above. You can reorder the keys if you want to silence the linter, but it’s not functionally required.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: CodeRabbit UI

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 0c088962934cdf829c9e6b282d2fa5a4e07723a3 and 41287db62997e2a54a1084037a90136517fcbbe5.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `.github/workflows/docker-server-test.yaml` (1 hunks)
* `apps/backend/.env.development` (1 hunks)
* `apps/backend/scripts/clickhouse-migrations.ts` (1 hunks)
* `apps/backend/src/lib/clickhouse.tsx` (1 hunks)
* `docker/server/.env.example` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>**/*.{ts,tsx}</summary>


**📄 CodeRabbit inference engine (AGENTS.md)**

> `**/*.{ts,tsx}`: Ensure code passes `pnpm typecheck` for TypeScript type validation
> Never use `toast` for blocking alerts and errors; use alerts instead as they are more visible to users
> Keep hover/click transitions snappy and fast; apply transitions after the action (e.g., smooth fade-out on hover end) rather than delaying actions with pre-transitions to avoid sluggish UI
> Never use try-catch-all, never void a promise, never use .catch(console.error) or similar; use `runAsynchronously` or `runAsynchronouslyWithAlert` for error handling instead of try-catch blocks
> Use loading indicators instead of try-catch blocks for asynchronous UI operations; button components like <Button> support async callbacks with built-in loading state
> Use ES6 maps instead of records wherever possible

Files:
- `apps/backend/src/lib/clickhouse.tsx`
- `apps/backend/scripts/clickhouse-migrations.ts`

</details>
<details>
<summary>apps/**/*.{ts,tsx}</summary>


**📄 CodeRabbit inference engine (AGENTS.md)**

> Prefer client components and dynamic functions like `usePathname` over Next.js dynamic functions to keep pages static; avoid using `await params` or similar dynamic patterns

Files:
- `apps/backend/src/lib/clickhouse.tsx`
- `apps/backend/scripts/clickhouse-migrations.ts`

</details>

</details><details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>📚 Learning: 2025-11-25T02:09:03.104Z</summary>

Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: Applies to packages/stack-shared/src/config/** : When making backwards-incompatible changes to the config schema, update the migration functions in packages/stack-shared/src/config/schema.ts


**Applied to files:**
- `apps/backend/scripts/clickhouse-migrations.ts`

</details>

</details><details>
<summary>🧬 Code graph analysis (2)</summary>

<details>
<summary>apps/backend/src/lib/clickhouse.tsx (1)</summary><blockquote>

<details>
<summary>packages/stack-shared/src/utils/env.tsx (1)</summary>

* `getEnvVariable` (16-58)

</details>

</blockquote></details>
<details>
<summary>apps/backend/scripts/clickhouse-migrations.ts (2)</summary><blockquote>

<details>
<summary>apps/backend/src/lib/clickhouse.tsx (1)</summary>

* `createClickhouseClient` (11-19)

</details>
<details>
<summary>packages/stack-shared/src/utils/env.tsx (1)</summary>

* `getEnvVariable` (16-58)

</details>

</blockquote></details>

</details><details>
<summary>🪛 dotenv-linter (4.0.0)</summary>

<details>
<summary>docker/server/.env.example</summary>

[warning] 20-20: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_PASSWORD key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)

---

[warning] 21-21: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_PASSWORD key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)

</details>
<details>
<summary>apps/backend/.env.development</summary>

[warning] 75-75: [SubstitutionKey] The STACK_CLICKHOUSE_URL key is not assigned properly

(SubstitutionKey)

---

[warning] 76-76: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_USER key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)

---

[warning] 77-77: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_PASSWORD key should go before the STACK_CLICKHOUSE_ADMIN_USER key

(UnorderedKey)

---

[warning] 78-78: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_USER key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)

---

[warning] 79-79: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_PASSWORD key should go before the STACK_CLICKHOUSE_EXTERNAL_USER key

(UnorderedKey)

---

[warning] 80-80: [UnorderedKey] The STACK_CLICKHOUSE_DATABASE key should go before the STACK_CLICKHOUSE_EXTERNAL_PASSWORD key

(UnorderedKey)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)</summary>

* GitHub Check: Vercel Agent Review
* GitHub Check: docker
* GitHub Check: restart-dev-and-test-with-custom-base-port
* GitHub Check: check_prisma_migrations (22.x)
* GitHub Check: setup-tests
* GitHub Check: build (22.x)
* GitHub Check: lint_and_build (latest)
* GitHub Check: all-good
* GitHub Check: build (22.x)
* GitHub Check: restart-dev-and-test
* GitHub Check: build (22.x)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread docker/server/.env.example
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
docker/server/.env.example (1)

19-21: Reorder ClickHouse keys for consistency with dotenv-linter and env-var conventions.

The three ClickHouse environment variables should be in alphabetical order to match the Postgres connection strings pattern and resolve the dotenv-linter UnorderedKey warnings.

Apply this diff:

-STACK_CLICKHOUSE_URL=http://host.docker.internal:8133
 STACK_CLICKHOUSE_ADMIN_PASSWORD=password
 STACK_CLICKHOUSE_EXTERNAL_PASSWORD=password
+STACK_CLICKHOUSE_URL=http://host.docker.internal:8133
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41287db and 1320221.

📒 Files selected for processing (1)
  • docker/server/.env.example (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-25T02:09:03.104Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T02:09:03.104Z
Learning: When making dashboard changes, provide deep links to the dashboard page in the format `http://localhost:<$NEXT_PUBLIC_STACK_PORT_PREFIX>01/projects/-selector-/...` (or use a.localhost, b.localhost, c.localhost for port prefixes 91, 92, 93)

Applied to files:

  • docker/server/.env.example
🪛 dotenv-linter (4.0.0)
docker/server/.env.example

[warning] 20-20: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_PASSWORD key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)


[warning] 21-21: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_PASSWORD key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: build (22.x)
  • GitHub Check: all-good
  • GitHub Check: restart-dev-and-test
  • GitHub Check: docker
🔇 Additional comments (1)
docker/server/.env.example (1)

19-21: ✓ Critical issue resolved: ClickHouse URL correctly targets host-exposed service.

The change from localhost:8133 to host.docker.internal:8133 ensures the server container correctly reaches the ClickHouse service. This aligns with the Postgres connection pattern and will allow ClickHouse operations to function properly in Docker environments.

@N2D4 N2D4 self-requested a review November 26, 2025 18:44
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/backend/scripts/clickhouse-migrations.ts (2)

14-14: GRANT statement references non-existent table.

This grants SELECT on analytics.allowed_table1, which doesn't exist yet and will cause the migration to fail.

Comment or remove this line until the table is created in a prior migration step.


22-23: Move client cleanup to a finally block.

If any query fails before line 23, the client won't be closed, leaving the connection open.

Apply this diff to guarantee cleanup:

-  console.log("Clickhouse migrations complete");
-  await client.close();
+  try {
+    // existing migration logic here
+    console.log("Clickhouse migrations complete");
+  } finally {
+    await client.close();
+  }

Note: Per coding guidelines, avoid try-catch-all for error handling. Let errors propagate naturally while ensuring cleanup in the finally block.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0077d16 and 62c6646.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • apps/backend/package.json (1 hunks)
  • apps/backend/scripts/clickhouse-migrations.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: For blocking alerts and errors, never use toast, as they are easily missed by the user. Instead, use alerts
Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error). Use runAsynchronously or runAsynchronouslyWithAlert instead for asynchronous error handling
When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g., transition-colors hover:transition-none)
Use ES6 maps instead of records wherever possible

Files:

  • apps/backend/scripts/clickhouse-migrations.ts
🧠 Learnings (1)
📚 Learning: 2025-11-28T21:21:39.123Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.123Z
Learning: Applies to packages/stack-shared/src/config/schema.ts : Whenever making backwards-incompatible changes to the config schema, update the migration functions in `packages/stack-shared/src/config/schema.ts`

Applied to files:

  • apps/backend/scripts/clickhouse-migrations.ts
🧬 Code graph analysis (1)
apps/backend/scripts/clickhouse-migrations.ts (2)
apps/backend/src/lib/clickhouse.tsx (1)
  • createClickhouseClient (11-19)
packages/stack-shared/src/utils/env.tsx (1)
  • getEnvVariable (16-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: docker
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
🔇 Additional comments (1)
apps/backend/package.json (1)

46-46: Version 1.14.0 is current and has no known vulnerabilities.

The @clickhouse/client package version 1.14.0 is the latest available on npm with no direct security vulnerabilities reported in Snyk or other vulnerability databases.

Comment thread apps/backend/scripts/clickhouse-migrations.ts
Comment thread apps/backend/scripts/clickhouse-migrations.ts
@cmux-agent
Copy link
Copy Markdown

cmux-agent bot commented Dec 8, 2025

Older cmux preview screenshots (latest comment is below)

Preview Screenshots

Open Workspace (1 hr expiry) · Open Dev Browser (1 hr expiry) · Open Diff Heatmap

Captured 3 screenshots for commit 20b597f (2025-12-08 18:39:32.957 UTC).

Element screenshot of the new ClickHouse service tile at port 8133

clickhouse-tile.png

Full page screenshot of the Dev Launchpad showing the new ClickHouse and MCPJam Inspector service tiles added in this PR, along with ClickHouse in the Background services list

dev-launchpad-full.png

Element screenshot of the new MCPJam Inspector service tile at port 8126

mcpjam-inspector-tile.png


Generated by cmux preview system

Comment thread apps/backend/scripts/db-migrations.ts
Comment thread docker/dependencies/docker.compose.yaml Outdated
Comment thread docker/dependencies/docker.compose.yaml Outdated
Comment thread apps/dev-launchpad/public/index.html Outdated
Comment thread apps/dev-launchpad/public/index.html Outdated
Comment thread apps/backend/src/app/api/latest/analytics/query/route.tsx Outdated
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/src/app/api/latest/analytics/query/route.tsx Outdated
Comment thread apps/backend/scripts/clickhouse-migrations.ts
Comment thread apps/backend/scripts/clickhouse-migrations.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
.github/workflows/docker-server-build-run.yaml (1)

26-30: ClickHouse setup step looks good and maintains consistency.

The step is well-configured:

  • Uses the same ClickHouse version (25.10) as the docker-compose file for consistency
  • Port mapping (8133:8123) aligns with the development environment configuration
  • Environment variables match those in .env.development
  • Logging output helps with debugging startup issues

Consider whether 5 seconds is sufficient for ClickHouse to fully initialize. Depending on the CI environment performance, you might want to add a health check loop similar to the "Check server health" step, or increase the sleep duration to ensure ClickHouse is ready before subsequent steps.

apps/backend/.env.development (1)

75-82: Consider alphabetically reordering the ClickHouse configuration keys for improved maintainability.

While the variable substitution pattern is already supported via the backend's custom environment variable handling, the ClickHouse keys should follow alphabetical order: STACK_CLICKHOUSE_ADMIN_PASSWORD, STACK_CLICKHOUSE_ADMIN_USER, STACK_CLICKHOUSE_DATABASE, STACK_CLICKHOUSE_EXTERNAL_PASSWORD, STACK_CLICKHOUSE_EXTERNAL_USER, STACK_CLICKHOUSE_URL.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20b597f and 73407b3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • .github/workflows/docker-server-build-run.yaml (1 hunks)
  • apps/backend/.env.development (1 hunks)
  • apps/backend/package.json (1 hunks)
  • apps/dev-launchpad/public/index.html (2 hunks)
  • docker/dependencies/docker.compose.yaml (2 hunks)
  • packages/stack-shared/src/known-errors.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/backend/package.json
  • apps/dev-launchpad/public/index.html
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Always add new E2E tests when changing the API or SDK interface
For blocking alerts and errors, never use toast; use alerts instead as they are less easily missed by the user
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error); use loading indicators and async callbacks instead, or use runAsynchronously/runAsynchronouslyWithAlert for error handling
Use ES6 maps instead of records wherever you can

Files:

  • packages/stack-shared/src/known-errors.tsx
**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,css}: Keep hover/click transitions snappy and fast; avoid fade-in delays on hover. Apply transitions after action completion instead, like smooth fade-out when hover ends
Use hover-exit transitions instead of hover-enter transitions; for example, use 'transition-colors hover:transition-none' instead of fade-in on hover

Files:

  • packages/stack-shared/src/known-errors.tsx
{.env*,**/*.{ts,tsx,js}}

📄 CodeRabbit inference engine (AGENTS.md)

Prefix environment variables with STACK_ (or NEXT_PUBLIC_STACK_ if public) so changes are picked up by Turborepo and improves readability

Files:

  • packages/stack-shared/src/known-errors.tsx
🧠 Learnings (1)
📚 Learning: 2025-12-04T18:03:49.984Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T18:03:49.984Z
Learning: Applies to {.env*,**/*.{ts,tsx,js}} : Prefix environment variables with STACK_ (or NEXT_PUBLIC_STACK_ if public) so changes are picked up by Turborepo and improves readability

Applied to files:

  • apps/backend/.env.development
🪛 dotenv-linter (4.0.0)
apps/backend/.env.development

[warning] 77-77: [SubstitutionKey] The STACK_CLICKHOUSE_URL key is not assigned properly

(SubstitutionKey)


[warning] 78-78: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_USER key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)


[warning] 79-79: [UnorderedKey] The STACK_CLICKHOUSE_ADMIN_PASSWORD key should go before the STACK_CLICKHOUSE_ADMIN_USER key

(UnorderedKey)


[warning] 80-80: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_USER key should go before the STACK_CLICKHOUSE_URL key

(UnorderedKey)


[warning] 81-81: [UnorderedKey] The STACK_CLICKHOUSE_EXTERNAL_PASSWORD key should go before the STACK_CLICKHOUSE_EXTERNAL_USER key

(UnorderedKey)


[warning] 82-82: [UnorderedKey] The STACK_CLICKHOUSE_DATABASE key should go before the STACK_CLICKHOUSE_EXTERNAL_PASSWORD key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests-with-custom-base-port
  • GitHub Check: setup-tests
  • GitHub Check: restart-dev-and-test
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
  • GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
  • GitHub Check: check_prisma_migrations (22.x)
🔇 Additional comments (2)
docker/dependencies/docker.compose.yaml (1)

208-226: ClickHouse service configuration looks good.

The ClickHouse service is well-configured with:

  • Specific image version (25.10) for reproducibility
  • Proper environment variables for database initialization
  • Persistent volume mount
  • Increased ulimits for production-like behavior
packages/stack-shared/src/known-errors.tsx (1)

1636-1656: LGTM! Analytics error constructors follow established patterns.

The new AnalyticsQueryTimeout and AnalyticsQueryError error constructors are well-implemented:

  • Follow the existing createKnownErrorConstructor pattern consistently
  • Use appropriate 400 status codes for client errors
  • Include descriptive messages and properly structured details objects
  • Correctly implement constructorArgsFromJson for deserialization
  • Properly exported in the KnownErrors collection

Also applies to: 1788-1789

Comment thread docker/dependencies/docker.compose.yaml Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
apps/backend/scripts/clickhouse-migrations.ts (2)

14-14: Migration will fail: analytics.allowed_table1 doesn't exist.

This GRANT references a table that hasn't been created. The migration will fail at runtime. Per past discussion, this is noted as temporary, but it should be commented out or removed until the table exists.


9-21: Add try-finally to ensure client cleanup on failure.

If any client.exec() call throws, client.close() on line 23 won't be reached, causing a resource leak. Wrap the migration logic in a try-finally block.

 export async function runClickhouseMigrations() {
   console.log("[Clickhouse] Running Clickhouse migrations...");
-  const client = clickhouseAdminClient;
+  const client = createClickhouseClient("admin");
   const clickhouseExternalPassword = getEnvVariable("STACK_CLICKHOUSE_EXTERNAL_PASSWORD");
-  // todo: create migration files
-  await client.exec({
-    query: "CREATE USER IF NOT EXISTS limited_user IDENTIFIED WITH plaintext_password BY {clickhouseExternalPassword:String}",
-    query_params: { clickhouseExternalPassword },
-  });
-  const queries = [
-    "GRANT SELECT ON analytics.allowed_table1 TO limited_user;",
-    "REVOKE ALL ON system.* FROM limited_user;",
-    "REVOKE CREATE, ALTER, DROP, INSERT ON *.* FROM limited_user;"
-  ];
-  for (const query of queries) {
-    console.log("[Clickhouse] " + query);
-    await client.exec({ query });
+  try {
+    await client.exec({
+      query: "CREATE USER IF NOT EXISTS limited_user IDENTIFIED WITH plaintext_password BY {clickhouseExternalPassword:String}",
+      query_params: { clickhouseExternalPassword },
+    });
+    const queries = [
+      "GRANT SELECT ON analytics.allowed_table1 TO limited_user;",
+      "REVOKE ALL ON system.* FROM limited_user;",
+      "REVOKE CREATE, ALTER, DROP, INSERT ON *.* FROM limited_user;"
+    ];
+    for (const query of queries) {
+      console.log("[Clickhouse] " + query);
+      await client.exec({ query });
+    }
+    console.log("[Clickhouse] Clickhouse migrations complete");
+  } finally {
+    await client.close();
   }
-  console.log("[Clickhouse] Clickhouse migrations complete");
-  await client.close();
 }
🧹 Nitpick comments (2)
apps/backend/src/app/api/latest/internal/analytics/query/route.ts (1)

52-53: Consider wrapping getQueryTimingStats errors.

If getQueryTimingStats fails (e.g., query log entry not found), it throws a StackAssertionError which will propagate as an internal error rather than a user-friendly AnalyticsQueryError. Consider wrapping this call for consistent error responses.

     const rows = await resultSet.data.json<Record<string, unknown>[]>();
-    const stats = await getQueryTimingStats(client, queryId);
+    let stats;
+    try {
+      stats = await getQueryTimingStats(client, queryId);
+    } catch (error) {
+      const message = error instanceof Error ? error.message : "Failed to retrieve query timing statistics";
+      throw new KnownErrors.AnalyticsQueryError(message);
+    }
apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (1)

217-239: Test timeout behavior may be unstable across ClickHouse versions

The SELECT sleep(3) with 100ms timeout can be affected by ClickHouse versions where sleep queries behave inconsistently with max_execution_time enforcement. Recent ClickHouse versions show timeout behavior inconsistencies where max_execution_time is sometimes treated differently.

Consider adding an inline comment explaining that the test expects ANALYTICS_QUERY_ERROR due to server-side timeout enforcement, and note any specific ClickHouse version constraints if the timeout behavior is known to be reliable only in certain versions.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73407b3 and f6fb8cf.

📒 Files selected for processing (6)
  • apps/backend/scripts/clickhouse-migrations.ts (1 hunks)
  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts (1 hunks)
  • apps/backend/src/lib/clickhouse.tsx (1 hunks)
  • apps/dev-launchpad/public/index.html (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (1 hunks)
  • docker/dependencies/docker.compose.yaml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dev-launchpad/public/index.html
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Always add new E2E tests when changing the API or SDK interface
For blocking alerts and errors, never use toast; use alerts instead as they are less easily missed by the user
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error); use loading indicators and async callbacks instead, or use runAsynchronously/runAsynchronouslyWithAlert for error handling
Use ES6 maps instead of records wherever you can

Files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/src/lib/clickhouse.tsx
**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,css}: Keep hover/click transitions snappy and fast; avoid fade-in delays on hover. Apply transitions after action completion instead, like smooth fade-out when hover ends
Use hover-exit transitions instead of hover-enter transitions; for example, use 'transition-colors hover:transition-none' instead of fade-in on hover

Files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/src/lib/clickhouse.tsx
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

NEVER use Next.js dynamic functions if you can avoid them; prefer using client components and hooks like usePathname instead of await params to keep pages static

Files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/src/lib/clickhouse.tsx
{.env*,**/*.{ts,tsx,js}}

📄 CodeRabbit inference engine (AGENTS.md)

Prefix environment variables with STACK_ (or NEXT_PUBLIC_STACK_ if public) so changes are picked up by Turborepo and improves readability

Files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/src/lib/clickhouse.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer .toMatchInlineSnapshot over other selectors in tests when possible; check snapshot-serializer.ts for formatting details

Files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
apps/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Always add new E2E tests when changing API or SDK interface; err on the side of creating too many tests due to the critical nature of the industry

Files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
apps/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Check existing apps for inspiration when implementing new apps or pages; update apps-frontend.tsx and apps-config.ts to add new apps

Files:

  • apps/backend/src/lib/clickhouse.tsx
🧠 Learnings (5)
📚 Learning: 2025-12-17T01:23:07.460Z
Learnt from: N2D4
Repo: stack-auth/stack-auth PR: 1032
File: apps/backend/src/app/api/latest/analytics/query/route.tsx:20-20
Timestamp: 2025-12-17T01:23:07.460Z
Learning: In apps/backend/src/app/api/latest/analytics/query/route.tsx, the include_all_branches field controls which ClickHouse user type is used: when true, use "admin" authType for access to all branches; when false (default), use "external" authType for limited/filtered branch access.

Applied to files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
  • apps/backend/scripts/clickhouse-migrations.ts
  • apps/backend/src/lib/clickhouse.tsx
📚 Learning: 2025-12-04T18:03:49.984Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T18:03:49.984Z
Learning: Applies to **/*.{ts,tsx} : NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error); use loading indicators and async callbacks instead, or use runAsynchronously/runAsynchronouslyWithAlert for error handling

Applied to files:

  • apps/backend/src/app/api/latest/internal/analytics/query/route.ts
📚 Learning: 2025-12-04T18:03:49.984Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T18:03:49.984Z
Learning: Applies to apps/e2e/**/*.{ts,tsx} : Always add new E2E tests when changing API or SDK interface; err on the side of creating too many tests due to the critical nature of the industry

Applied to files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
📚 Learning: 2025-12-04T18:03:49.984Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T18:03:49.984Z
Learning: Applies to **/*.{ts,tsx} : Always add new E2E tests when changing the API or SDK interface

Applied to files:

  • apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts
📚 Learning: 2025-12-04T18:03:49.984Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T18:03:49.984Z
Learning: Applies to packages/stack-shared/src/config/schema.ts : Whenever making backwards-incompatible changes to the config schema, update the migration functions in packages/stack-shared/src/config/schema.ts

Applied to files:

  • apps/backend/scripts/clickhouse-migrations.ts
🧬 Code graph analysis (2)
apps/backend/src/app/api/latest/internal/analytics/query/route.ts (4)
apps/backend/src/route-handlers/smart-route-handler.tsx (1)
  • createSmartRouteHandler (211-296)
packages/stack-shared/src/schema-fields.ts (8)
  • yupObject (247-251)
  • adminAuthTypeSchema (499-499)
  • adaptSchema (330-330)
  • yupBoolean (195-198)
  • yupString (187-190)
  • yupRecord (283-322)
  • yupMixed (210-212)
  • jsonSchema (410-410)
apps/backend/src/prisma-client.tsx (1)
  • client (133-138)
apps/backend/src/lib/clickhouse.tsx (2)
  • clickhouseExternalClient (22-22)
  • getQueryTimingStats (24-60)
apps/backend/src/lib/clickhouse.tsx (2)
packages/stack-shared/src/utils/env.tsx (1)
  • getEnvVariable (16-58)
packages/stack-shared/src/utils/errors.tsx (1)
  • StackAssertionError (69-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: all-good
  • GitHub Check: Vercel Agent Review
  • GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
  • GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests-with-custom-base-port
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: restart-dev-and-test
🔇 Additional comments (6)
docker/dependencies/docker.compose.yaml (1)

208-226: ClickHouse service configuration looks good.

The service is properly configured with appropriate ports, environment variables, volume mount, and ulimits for file descriptors. The port conflict with drizzle-gateway has been resolved by moving drizzle-gateway to port suffix 35.

apps/backend/src/app/api/latest/internal/analytics/query/route.ts (1)

8-67: Good use of singleton client pattern.

Using the pre-configured clickhouseExternalClient singleton avoids the per-request client creation and resource leak issues flagged in past reviews. The route structure follows the established patterns with proper schema validation.

apps/e2e/tests/backend/endpoints/api/v1/analytics-query.test.ts (1)

4-382: Comprehensive E2E test coverage for the analytics query endpoint.

The tests cover:

  • Basic query execution with admin access
  • Parameterized queries (single and multiple params)
  • Custom timeout handling
  • Required field validation
  • Invalid SQL handling
  • Multiple row results
  • Tenancy ID verification
  • Security restrictions (CREATE, system tables, KILL, INSERT)

This aligns well with the coding guidelines requiring E2E tests for API changes.

apps/backend/src/lib/clickhouse.tsx (3)

5-10: Environment variables correctly use STACK_ prefix.

The environment variables follow the coding guidelines with the STACK_CLICKHOUSE_* prefix, ensuring they're picked up by Turborepo and maintaining naming consistency.


52-59: Proper validation for query log results.

The code now validates that exactly one result is returned from the query log and throws a StackAssertionError with context if not, addressing the past review concern about undefined access.


21-22: Singleton clients created at module load time.

The singleton clients are instantiated when the module is imported. If required environment variables (like STACK_CLICKHOUSE_URL) are missing, this will throw at startup rather than at first use. This matches the pattern used elsewhere (e.g., Prisma client) and provides early failure detection.

Comment thread apps/backend/scripts/clickhouse-migrations.ts Outdated
Comment thread apps/backend/src/app/api/latest/internal/analytics/query/route.ts
Comment thread apps/backend/scripts/db-migrations.ts
Comment thread packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dev-launchpad/public/index.html (1)

123-135: Fix port suffix collision on "33".

Both "ClickHouse native interface" (line 133, backgroundServices) and "Drizzle Gateway" (line 302, apps) use suffix "33". Since the port formula concatenates ${stackPortPrefix}${suffix}, both services will attempt to bind to the same port (e.g., 8133 with default prefix 81), causing a startup failure. Change one of the suffixes to an unused value.

@N2D4 N2D4 merged commit 484c3a6 into dev Jan 28, 2026
24 of 27 checks passed
@N2D4 N2D4 deleted the clickhouse-setup branch January 28, 2026 17:12
@coderabbitai coderabbitai bot mentioned this pull request Mar 2, 2026
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