Skip to content

feat(project): Added projects#90

Closed
SteakFisher wants to merge 8 commits into
mainfrom
feat/project
Closed

feat(project): Added projects#90
SteakFisher wants to merge 8 commits into
mainfrom
feat/project

Conversation

@SteakFisher

Copy link
Copy Markdown
Member

No description provided.

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

  • Adds project scoping across authentication context, API keys, users, metadata, sessions, events, tags, expressions, webhooks, and deliveries.
  • Updates HTTP and gRPC routes to carry and enforce projectId through request handling.
  • Adds onboarding that creates a project, metadata, Dodo webhooks, and a dashboard API key.
  • Updates billing, event ingestion, event querying, tag lookup, and expression resolution paths for project-aware data access.

Confidence Score: 3/5

Merge safety is reduced by project-isolation and billing-accounting issues in the new project-scoped paths.

The changes cover core auth, storage, billing, and query behavior, and the remaining issues can cause cross-project ingestion collisions, incorrect billing windows, and under-reported AI token charges.

src/storage/db/postgres/schema.ts; src/storage/adapter/clickhouse/utils.ts; src/storage/adapter/clickhouse/handlers/priceRequestAiTokenUsage.ts; src/storage/adapter/postgres/handlers/queryEvents.ts; src/storage/adapter/clickhouse/handlers/queryEvents.ts

T-Rex T-Rex Logs

What T-Rex did

  • Attempted to start the repository's Postgres test database with docker compose and apply the Drizzle schema, but Docker was not installed in the environment.
  • Created a targeted Bun repro script to exercise the scope of the last_billed_timestamp lookup by inserting two users with the same ID in different projects and capturing the generated lookup SQL and ClickHouse query parameters.
  • Ran a focused runtime harness modeling the ClickHouse pricing expression against an event with metrics.debit_amount.output_cache set, and observed that the generated SQL sums input, input_cache, and output but omits output_cache, leading to a billed total of 0 for output_cache=12345.
  • Executed a Bun test harness against Postgres and ClickHouse queryEvents with mocked DB clients, and observed that debitAmount was 0 and SUM(debitAmount) was 0, with the generated SQL omitting output_cache.
  • Compared onboarding-projects baselines and head state, noting that no Postgres-backed route request completed.
  • Compared API key handling before and after commits and found that base allowed API keys without a projectId, while head added a dashboard API key tied to a projectId.
  • Attempted grpc-project-isolation tests; both before and after show Postgres connection refused (EXIT_CODE: 1), blocked by Docker unavailability and no Postgres service listening.
  • Generated Postgres project schema before and after commits; base shows minimal schema with a unique index on api_keys and no project-related tables, while head adds projects, project_id, keys, constraints, and foreign keys.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. src/storage/adapter/clickhouse/utils.ts, line 15-27 (link)

    P1 Scope billed lookup

    usersTable is now scoped by (projectId, id), but this lookup still reads by userId alone. If two projects both have the same user id and one project has already advanced last_billed_timestamp, ClickHouse checkout pricing for the other project can use that timestamp and skip billable usage from its own project. Pass auth.projectId into this helper and include it in the usersTable filter.

  2. src/storage/adapter/postgres/handlers/queryEvents.ts, line 106-113 (link)

    P1 Report full debit

    AI token events now persist metrics.debit_amount.output_cache, but the query API’s synthetic debitAmount field and aggregate omit that component in both query adapters. In src/storage/adapter/postgres/handlers/queryEvents.ts and src/storage/adapter/clickhouse/handlers/queryEvents.ts, rows and SUM(debitAmount) queries under-report AI usage whenever output-cache pricing is non-zero. Include output_cache in both the selected value and aggregate expression in each adapter.

    Artifacts

    Repro: executable Bun test harness for Postgres and ClickHouse queryEvents debitAmount under-reporting

    • Contains supporting evidence from the run (text/typescript; charset=utf-8).

    Repro: Bun test output showing inserted metrics, handler responses, and generated SQL omitting output_cache

    • Keeps the command output available without making the summary code-heavy.

    View artifacts

    T-Rex Ran code and verified through T-Rex

Reviews (8): Last reviewed commit: "fix: resolve all greptile findings — bil..." | Re-trigger Greptile

Comment thread src/routes/http/api/onboarding.ts
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

Comment thread src/storage/db/postgres/helpers/users.ts Outdated
.references(() => projectsTable.id)
.notNull(),
eventId: uuid("event_id").notNull(),
idempotencyKey: text("idempotency_key").notNull().unique(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Global idempotency collision

idempotencyKey is still globally unique after adding projectId to the usage event tables. When Project A records idempotencyKey="checkout-1", Project B cannot independently use the same idempotency key because Postgres rejects the insert before the project scope is considered. This makes one project's events able to block another project's ingestion. The uniqueness should be scoped to (projectId, idempotencyKey) for both basic usage and AI token usage events.

Comment on lines 6 to 7
const VALUE_EXPR =
"JSONExtractInt(metrics, 'debit_amount', 'input') + JSONExtractInt(metrics, 'debit_amount', 'input_cache') + JSONExtractInt(metrics, 'debit_amount', 'output')";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Include output cache

The ClickHouse AI price expression stores debit_amount.output_cache, but this billing expression does not sum it. When a project prices output-cache tokens with outputCacheTag, outputCacheExpr, or outputCacheAmount, checkout billing undercharges those events. Include output_cache here so ClickHouse pricing matches the stored metrics and the Postgres pricing path.

Suggested change
const VALUE_EXPR =
"JSONExtractInt(metrics, 'debit_amount', 'input') + JSONExtractInt(metrics, 'debit_amount', 'input_cache') + JSONExtractInt(metrics, 'debit_amount', 'output')";
const VALUE_EXPR =
"JSONExtractInt(metrics, 'debit_amount', 'input') + JSONExtractInt(metrics, 'debit_amount', 'input_cache') + JSONExtractInt(metrics, 'debit_amount', 'output_cache') + JSONExtractInt(metrics, 'debit_amount', 'output')";
Artifacts

Repro: executable output-cache pricing harness

  • Contains supporting evidence from the run (text/javascript; charset=utf-8).

Repro: harness output showing SQL omits output_cache and computes zero

  • Keeps the command output available without making the summary code-heavy.

View artifacts

T-Rex Ran code and verified through T-Rex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant