feat: default retention to metadata-only, add data storage billing - #1243
Conversation
WalkthroughAdds end-to-end per-request data storage cost: DB column and migration, gateway utility to compute and include Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client as Client
participant Chat as Chat Handler
participant Calc as calculateDataStorageCost()
participant Logs as insertLog
participant Worker as Worker
participant DB as Database
participant API as Activity API
participant UI as Dashboard
Note over Chat,Calc: request-time cost calculation (new)
Client->>Chat: send chat request
Chat->>Calc: calculateDataStorageCost(prompt,cached,completion,reasoning)
Calc-->>Chat: dataStorageCost (string)
Chat->>Logs: insertLog({... , dataStorageCost })
Logs->>Worker: enqueue/process log row (includes data_storage_cost)
Worker->>DB: INSERT/UPDATE log row (data_storage_cost)
Note over API,DB: daily aggregation includes dataStorageCost
UI->>API: GET /activity
API->>DB: SELECT COALESCE(SUM(data_storage_cost),0) per day
DB-->>API: daily aggregates incl. dataStorageCost
API-->>UI: activity array with dataStorageCost
UI->>UI: render storage line and chart slice when > 0
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (6)**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/ui/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/{ui,playground}/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/{ui,playground}/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⏰ 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). (8)
🔇 Additional comments (7)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
apps/ui/src/components/settings/organization-retention-settings.tsx (2)
27-29: Sync retentionLevel with selectedOrganization and default to "none"
retentionLevelis initialized once fromselectedOrganization?.retentionLevel || "retain"and never updated if the selected organization changes, and the fallback still assumes"retain"even though the DB default is now"none". That can leave the UI showing stale or wrong values when switching orgs or when org data loads asynchronously.Consider:
- Defaulting to
"none"to align with the new schema default.- Adding a
React.useEffectthat resetsretentionLevelwheneverselectedOrganization.id/retentionLevelchanges so the form always reflects the active org.
145-162: Alert copy matches behavior but duplicates retention/pricing constantsThe new alert is clear and matches current behavior (Free: 3 days, Pro: 30 days, storage at $0.01 per 1M tokens including input/cached/output/reasoning). However, these numbers are now hard-coded here in addition to:
cleanupExpiredLogDatainapps/worker/src/worker.ts(3/30‑day retention).calculateDataStorageCostinapps/gateway/src/lib/logs.ts(pricing formula).To avoid future drift, consider centralizing these plan retention/pricing constants (e.g., shared config or vars module) and importing them into both backend and UI.
apps/gateway/src/lib/logs.ts (1)
84-104: Storage cost helper matches pricing; consider fixed precision for DB friendlinessThe implementation correctly computes storage cost as
$0.01 / 1Mover prompt + cached + completion + reasoning tokens and is tolerant of null/string inputs.To make persisted values more uniform (and avoid scientific notation for tiny totals), consider returning a fixed‑precision decimal, e.g.:
const cost = (totalTokens / 1_000_000) * 0.01; return cost.toFixed(8); // 1e-8 resolution per tokenThis still preserves per‑token granularity while keeping values predictable for the decimal column and downstream displays.
apps/gateway/src/chat/chat.ts (1)
3410-3454: Success logs use calculateDataStorageCost with estimated tokens; consider aligning with cost calculationFor both:
- Streaming success logs (around 3448–3453), and
- Non‑streaming success logs (around 4045–4050),
dataStorageCostis derived from the same (often estimated) prompt/cached/completion/reasoning token counts you already compute, which is exactly what you want for storage billing.One minor consistency tweak you might consider later:
calculateCostsin nearby code still uses the rawreasoningTokensvariable in some paths, while storage cost usescalculatedReasoningTokens. If you eventually want compute and storage to be based on the same token estimates, you could pass the calculated reasoning tokens intocalculateCostsas well.Also applies to: 4045-4050
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/playground/src/lib/api/v1.d.tsis excluded by!**/v1.d.tsapps/ui/src/lib/api/v1.d.tsis excluded by!**/v1.d.ts
📒 Files selected for processing (8)
apps/api/src/routes/activity.ts(4 hunks)apps/gateway/src/chat/chat.ts(11 hunks)apps/gateway/src/lib/logs.ts(1 hunks)apps/ui/src/components/dashboard/dashboard-client.tsx(2 hunks)apps/ui/src/components/settings/organization-retention-settings.tsx(1 hunks)apps/ui/src/types/activity.ts(2 hunks)apps/worker/src/worker.ts(1 hunks)packages/db/src/schema.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anytype assertions unless absolutely necessary
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
No unnecessary code comments
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/gateway/src/lib/logs.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsxapps/api/src/routes/activity.tsapps/worker/src/worker.tsapps/gateway/src/chat/chat.tsapps/ui/src/types/activity.tspackages/db/src/schema.ts
apps/{gateway,api}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{gateway,api}/**/*.{ts,tsx}: Use Hono web framework for backend services in Gateway and API applications
Use Zod schemas for validation in backend servicesUse Zod schemas for validation in Hono applications
Files:
apps/gateway/src/lib/logs.tsapps/api/src/routes/activity.tsapps/gateway/src/chat/chat.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/gateway/src/lib/logs.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsxapps/api/src/routes/activity.tsapps/worker/src/worker.tsapps/gateway/src/chat/chat.tsapps/ui/src/types/activity.tspackages/db/src/schema.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
Files:
apps/gateway/src/lib/logs.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsxapps/api/src/routes/activity.tsapps/worker/src/worker.tsapps/gateway/src/chat/chat.tsapps/ui/src/types/activity.tspackages/db/src/schema.ts
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{ui,playground}/**/*.{ts,tsx}: Use Next.js App Router with React Server Components in frontend applications
Usenext/linkfor links andnext/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applicationsUse
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsxapps/ui/src/types/activity.ts
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsxapps/ui/src/types/activity.ts
**/db/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/db/**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads, usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
For database schema changes, usepnpm run setupinstead of writing migrations which will generate .sql files
Always sync schema withpnpm run setupafter table/column changes
Files:
packages/db/src/schema.ts
🧠 Learnings (2)
📚 Learning: 2025-11-24T20:02:09.207Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T20:02:09.207Z
Learning: Applies to **/db/**/*.{ts,tsx} : Always sync schema with `pnpm run setup` after table/column changes
Applied to files:
packages/db/src/schema.ts
📚 Learning: 2025-11-24T20:02:09.207Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T20:02:09.207Z
Learning: Applies to **/db/**/*.{ts,tsx} : For database schema changes, use `pnpm run setup` instead of writing migrations which will generate .sql files
Applied to files:
packages/db/src/schema.ts
🧬 Code graph analysis (2)
apps/api/src/routes/activity.ts (1)
packages/db/src/index.ts (1)
tables(14-16)
apps/gateway/src/chat/chat.ts (1)
apps/gateway/src/lib/logs.ts (1)
calculateDataStorageCost(88-104)
⏰ 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). (9)
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (5)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (3)
- GitHub Check: build / run
- GitHub Check: test / run
- GitHub Check: autofix
- GitHub Check: lint / run
🔇 Additional comments (8)
apps/worker/src/worker.ts (1)
338-341: Pro retention window updated to 30 days as intendedThe
PRO_PLAN_RETENTION_DAYSconstant move to 30 days cleanly updates both the cutoff calculation and log messaging and matches the new UI copy.packages/db/src/schema.ts (1)
138-142: Schema changes for retention and dataStorageCost look consistent; ensure DB is synced
organization.retentionLevelnow defaulting to"none"matches the new default-retention behavior for orgs.log.dataStorageCostasdecimal().notNull().default("0")is compatible with how it’s summed in the activity route and displayed in the UI.Please make sure to run
pnpm run setup(and apply the generated migration) so the database schema is in sync with these column changes, as required for/dbmodules.Also applies to: 461-462
apps/ui/src/components/dashboard/dashboard-client.tsx (1)
89-103: Cost breakdown now includes storage; verify it matches whatcostrepresentsThe new aggregations for
totalRequestCostandtotalDataStorageCost, and the breakdown line (input + output + requests + storage), look consistent with the activity API additions.To avoid confusing users, please double‑check that
day.cost(and thustotalCost) is defined as:
inputCost + outputCost + requestCost + dataStorageCostIf
costexcludes storage (or requests), consider either:
- Computing the headline from the sum of these components, or
- Adjusting the breakdown so the numbers add up to the displayed total.
Also applies to: 323-342
apps/ui/src/types/activity.ts (1)
13-29: Activity types correctly mirror new backend fieldsExtending
DailyActivityandActivitTwithrequestCostanddataStorageCostkeeps the UI types aligned withdailyActivitySchemaand the dashboard aggregations.Also applies to: 35-55
apps/api/src/routes/activity.ts (1)
23-39: dataStorageCost is correctly aggregated and exposed in activity APIIncluding
dataStorageCostin the Zod schema, SQL aggregation (COALESCE(SUM(log.dataStorageCost), 0)), and the mappedactivityDataobjects is consistent with the new log column and the UI’s expectations.The explicit
Number(day.dataStorageCost)cast is appropriate given the decimal column type.Also applies to: 158-161, 239-267
apps/gateway/src/chat/chat.ts (3)
10-11: Centralizing storage-cost calculation via calculateDataStorageCostImporting
calculateDataStorageCostalongsideinsertLogensures all log callers use the same pricing logic for storage, rather than duplicating the$0.01 / 1M tokensformula in multiple places.
1745-1775: Cached responses correctly account for storage costFor both:
- Cached streaming responses (lines around 1813–1818), and
- Cached non‑streaming responses (lines around 1926–1931),
you compute
dataStorageCostfrom the appropriatepromptTokens,cachedTokens,completionTokens, andreasoningTokens. This ensures storage billing remains accurate even when serving from cache.Also applies to: 1887-1934
2131-2155: Using"0"dataStorageCost in error/canceled log paths is a sensible defaultIn the various canceled/error branches (streaming cancel, streaming fetch error, non‑stream fetch error, non‑stream canceled, non‑stream provider error), setting
dataStorageCost: "0"avoids nulls on the non‑nullable DB column and makes it clear that no billable storage tokens were recorded for these failed requests.Also applies to: 2213-2241, 3588-3617, 3675-3700, 3767-3812
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/gateway/src/lib/logs.ts (1)
84-104: Data‑storage cost helper is correct; consider explicit clamping/rounding.The implementation matches the stated pricing ($0.01 per 1M tokens) and safely handles
null/undefined/string inputs. Two optional refinements you might consider:
- Explicitly clamp non‑positive totals to
"0"(e.g.,if (!Number.isFinite(totalTokens) || totalTokens <= 0) return "0";) instead of relying onNumber(...) || 0to hideNaN.- Round to a fixed precision (e.g.,
toFixed(8)) if you want consistent decimals rather than possible exponential notation fromtoString().These are purely about observability/UX of the metric; the current logic is functionally sound.
apps/gateway/src/chat/chat.ts (2)
1813-1818: Consistent storage‑cost computation across cached and non‑cached success paths.The helper is wired correctly in all success cases:
- Cached streaming: uses
promptTokens,cachedTokens,completionTokens,reasoningTokensfrom the reconstructed usage.- Cached non‑streaming: uses
cachedResponse.usagefields.- Live streaming & non‑streaming: uses the calculated prompt/completion/reasoning tokens plus
cachedTokens.This keeps the data‑storage metric aligned with what you actually log in
promptTokens,completionTokens,cachedTokens, andreasoningTokens. One small follow‑up you might consider later:calculateCostsstill uses the originalreasoningTokensvariable, whereasdataStorageCost(and the loggedreasoningTokensfield) now usecalculatedReasoningTokens; if you ever want billing and storage to reflect the same reasoning‑token estimate, you may want to align those.Also applies to: 1926-1931, 3449-3453, 4045-4050
2152-2152: Zero storage cost for error/canceled logs—double‑check this matches billing intent.For all error and canceled flows (streaming + non‑streaming),
dataStorageCostis hard‑coded to"0", while successful flows usecalculateDataStorageCost(...). That means:
- You will not bill any data‑storage cost for partial/failed requests, even if some prompt/completion tokens were processed and stored in logs.
- Aggregated storage cost will effectively only reflect fully successful completions (plus cache hits), not traffic that errored or was canceled.
If the product requirement is “only bill storage for successful completions,” this is fine. If instead you want “bill storage for any tokens we persist, regardless of outcome,” you may want to call
calculateDataStorageCosthere too, using whatever token counts are available (often at least prompt tokens) rather than forcing zero.Please confirm which behavior you want long‑term so downstream analytics/UX can be interpreted correctly.
Also applies to: 2238-2238, 2387-2387, 3614-3614, 3697-3697, 3809-3809
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/playground/src/lib/api/v1.d.tsis excluded by!**/v1.d.tsapps/ui/src/lib/api/v1.d.tsis excluded by!**/v1.d.ts
📒 Files selected for processing (10)
apps/api/src/routes/activity.ts(4 hunks)apps/gateway/src/chat/chat.ts(11 hunks)apps/gateway/src/lib/logs.ts(1 hunks)apps/ui/src/components/dashboard/dashboard-client.tsx(2 hunks)apps/ui/src/components/settings/organization-retention-settings.tsx(1 hunks)apps/ui/src/types/activity.ts(2 hunks)apps/worker/src/worker.ts(1 hunks)packages/db/migrations/1764067852_thankful_ogun.sql(1 hunks)packages/db/migrations/meta/_journal.json(1 hunks)packages/db/src/schema.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anytype assertions unless absolutely necessary
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
No unnecessary code comments
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
packages/db/src/schema.tsapps/worker/src/worker.tsapps/gateway/src/lib/logs.tsapps/ui/src/types/activity.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/api/src/routes/activity.tsapps/ui/src/components/settings/organization-retention-settings.tsxapps/gateway/src/chat/chat.ts
**/db/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/db/**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads, usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
For database schema changes, usepnpm run setupinstead of writing migrations which will generate .sql files
Always sync schema withpnpm run setupafter table/column changes
Files:
packages/db/src/schema.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
packages/db/src/schema.tsapps/worker/src/worker.tsapps/gateway/src/lib/logs.tsapps/ui/src/types/activity.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/api/src/routes/activity.tsapps/ui/src/components/settings/organization-retention-settings.tsxapps/gateway/src/chat/chat.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
Files:
packages/db/src/schema.tsapps/worker/src/worker.tsapps/gateway/src/lib/logs.tsapps/ui/src/types/activity.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/api/src/routes/activity.tsapps/ui/src/components/settings/organization-retention-settings.tsxapps/gateway/src/chat/chat.ts
apps/{gateway,api}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{gateway,api}/**/*.{ts,tsx}: Use Hono web framework for backend services in Gateway and API applications
Use Zod schemas for validation in backend servicesUse Zod schemas for validation in Hono applications
Files:
apps/gateway/src/lib/logs.tsapps/api/src/routes/activity.tsapps/gateway/src/chat/chat.ts
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{ui,playground}/**/*.{ts,tsx}: Use Next.js App Router with React Server Components in frontend applications
Usenext/linkfor links andnext/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applicationsUse
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/types/activity.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/types/activity.tsapps/ui/src/components/dashboard/dashboard-client.tsxapps/ui/src/components/settings/organization-retention-settings.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T20:02:09.207Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T20:02:09.207Z
Learning: Applies to **/db/**/*.{ts,tsx} : Always sync schema with `pnpm run setup` after table/column changes
Applied to files:
packages/db/src/schema.ts
📚 Learning: 2025-11-24T20:02:09.207Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T20:02:09.207Z
Learning: Applies to **/db/**/*.{ts,tsx} : For database schema changes, use `pnpm run setup` instead of writing migrations which will generate .sql files
Applied to files:
packages/db/src/schema.ts
🧬 Code graph analysis (2)
apps/api/src/routes/activity.ts (1)
packages/db/src/index.ts (1)
tables(14-16)
apps/gateway/src/chat/chat.ts (1)
apps/gateway/src/lib/logs.ts (1)
calculateDataStorageCost(88-104)
⏰ 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). (3)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (4)
🔇 Additional comments (9)
apps/worker/src/worker.ts (1)
340-340: LGTM! Retention period updated to match marketing claims.The pro plan retention period has been correctly increased from 7 to 30 days, aligning with the PR objectives to match marketing communications.
packages/db/src/schema.ts (2)
142-142: LGTM! Default retention changed to metadata-only.The default retention level for new organizations has been correctly changed from "retain" to "none", making metadata-only storage the default as stated in the PR objectives. Note that existing organizations will retain their current settings since this only affects the default value.
Based on learnings, ensure you've run
pnpm run setupto sync the schema changes.
461-461: LGTM! Data storage cost column added safely.The new
dataStorageCostcolumn is properly defined as a non-null decimal with a default value of "0", ensuring safe migration for existing log records. This aligns with the PR's objective to track and bill for stored data.Based on learnings, ensure you've run
pnpm run setupto sync the schema changes.packages/db/migrations/1764067852_thankful_ogun.sql (1)
1-2: LGTM! Migration safely implements schema changes.The migration correctly:
- Adds the
data_storage_costcolumn with a safe default value for existing rows- Updates the
retention_leveldefault to 'none' for new organizationsBoth statements align with the schema changes and will execute without disrupting existing data.
packages/db/migrations/meta/_journal.json (1)
502-508: LGTM! Migration journal entry properly recorded.The new migration entry is correctly formatted and sequentially numbered, maintaining consistency with the existing journal structure.
apps/api/src/routes/activity.ts (1)
33-33: LGTM! Data storage cost properly integrated into activity tracking.The
dataStorageCostfield is correctly:
- Added to the response schema (line 33)
- Aggregated from logs using null-safe SQL (lines 158-161)
- Parsed from query results (line 249)
- Included in the returned activity data (line 266)
The implementation follows the same pattern as other cost fields (
inputCost,outputCost,requestCost) and uses appropriate null handling withCOALESCE.Also applies to: 158-161, 249-249, 266-266
apps/ui/src/types/activity.ts (1)
22-23: LGTM! Activity types updated to include cost fields.The type definitions correctly add
requestCostanddataStorageCostto bothDailyActivityandActivitT, aligning with the API response schema changes inapps/api/src/routes/activity.ts.Also applies to: 47-47
apps/ui/src/components/dashboard/dashboard-client.tsx (1)
100-103: LGTM! Dashboard correctly displays storage costs.The changes properly:
- Calculate
totalDataStorageCostby aggregating from activity data (lines 100-101)- Simplify
totalRequestCostto use the backend-provided value (line 103)- Conditionally render storage cost in the UI only when > 0 (lines 335-342)
The implementation follows the existing patterns for cost aggregation and display, providing clear visibility into storage billing.
Also applies to: 335-342
apps/gateway/src/chat/chat.ts (1)
10-10: Good reuse of shared cost helper for logging.Importing
calculateDataStorageCosthere centralizes the storage‑billing logic and keeps the chat route free of hard‑coded pricing constants, which will make future pricing changes easier.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/gateway/src/api.spec.ts(1 hunks)packages/db/migrations/1764067852_thankful_ogun.sql(1 hunks)packages/db/migrations/meta/_journal.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anytype assertions unless absolutely necessary
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
No unnecessary code comments
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/gateway/src/api.spec.ts
apps/{gateway,api}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{gateway,api}/**/*.{ts,tsx}: Use Hono web framework for backend services in Gateway and API applications
Use Zod schemas for validation in backend servicesUse Zod schemas for validation in Hono applications
Files:
apps/gateway/src/api.spec.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/gateway/src/api.spec.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
Files:
apps/gateway/src/api.spec.ts
⏰ 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). (10)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (3)
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (5)
- GitHub Check: e2e-shards (2)
- GitHub Check: test / run
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: autofix
🔇 Additional comments (3)
packages/db/migrations/1764067852_thankful_ogun.sql (1)
2-2: Verify retention level default change doesn't break existing logic.The default for
retention_levelchanges from'retain'to'none', which switches new organizations to metadata-only storage by default. This is intentional per the PR objectives, but confirm that:
- Downstream code that reads
retention_levelhandles'none'correctly- The UI properly reflects this change when displaying retention settings for new orgs
packages/db/migrations/meta/_journal.json (1)
502-508: Migration journal entry looks correct.The new entry properly documents the migration with correct sequencing (idx 71 after 70), matching timestamp, and format consistency.
apps/gateway/src/api.spec.ts (1)
69-69: Gateway test retention level change is correct.The explicit
retentionLevel: "retain"is appropriate because the tests verify full log content (line 142 checkslogs[0].content). The database now defaults to"none"(metadata-only), so this fixture explicitly opts into data retention to maintain test correctness.Verification confirms:
"retain"is a valid enum value (defined inpackages/db/src/schema.ts:139)- Default retention is
"none"per the schema (packages/db/src/schema.ts:142)Note: Other test files (logs.spec.ts, keys-api.spec.ts, keys-provider.spec.ts, activity.spec.ts) do not explicitly set
retentionLevel, so they will use the database default of"none". Ensure these tests don't inadvertently expect full log content to be retained.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/ui/src/components/dashboard/log-card.tsx(4 hunks)apps/ui/src/components/settings/organization-retention-settings.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/ui/src/components/settings/organization-retention-settings.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anytype assertions unless absolutely necessary
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
No unnecessary code comments
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{ui,playground}/**/*.{ts,tsx}: Use Next.js App Router with React Server Components in frontend applications
Usenext/linkfor links andnext/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applicationsUse
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/dashboard/log-card.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/ui/src/components/dashboard/log-card.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/dashboard/log-card.tsx
⏰ 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). (9)
- GitHub Check: autofix
- GitHub Check: lint / run
- GitHub Check: test / run
- GitHub Check: e2e-shards (4)
- GitHub Check: build / run
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (5)
- GitHub Check: e2e-shards (3)
- GitHub Check: e2e-shards (2)
🔇 Additional comments (3)
apps/ui/src/components/dashboard/log-card.tsx (3)
12-12: LGTM!The
Infoicon import is correctly placed with the other lucide-react icons and is used appropriately for the retention hint tooltip.
688-697: LGTM!The conditional rendering for the Message Context section is well-implemented, providing a clear fallback message that guides users on how to enable retention when message data is not available.
725-734: LGTM!The conditional rendering for the Response section follows the same pattern as the Message Context section, providing consistent user guidance when content is not retained.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/ui/src/components/dashboard/log-card.tsx (1)
82-113: Fix the terminology inconsistency flagged in the previous review.The tooltip at lines 106-107 says "Enable retention in project settings" but the Message Context and Response sections at lines 710-711 and 748-749 say "Enable retention in organization policies". This inconsistency was previously flagged but remains unresolved.
Apply this diff to align with the terminology used elsewhere in this file:
<TooltipContent> <p> - Enable retention in project settings to store response + Enable retention in organization policies to store response content </p> </TooltipContent>Alternatively, if "project settings" is the correct term, update lines 710-711 and 748-749 to match. Consider running a search to verify the correct terminology across the codebase:
#!/bin/bash # Search for retention-related settings terminology across the UI rg -nP --type=tsx --type=ts -C2 '(project settings|organization policies|organization settings).*retention|retention.*(project settings|organization policies|organization settings)' apps/ui/packages/db/migrations/1764081198_loud_eternals.sql (1)
1-1: Address the previous review feedback on numeric precision.The past review comment about using
numeric(12, 4) DEFAULT 0 NOT NULLfor financial data precision hasn't been addressed. The column still uses unboundednumericwith a string default.Based on past review feedback, apply this diff:
-ALTER TABLE "log" ADD COLUMN "data_storage_cost" numeric DEFAULT '0' NOT NULL; +ALTER TABLE "log" ADD COLUMN "data_storage_cost" numeric(12, 4) DEFAULT 0 NOT NULL;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/gateway/src/chat/chat.ts(11 hunks)apps/ui/src/components/dashboard/log-card.tsx(4 hunks)packages/db/migrations/1764081198_loud_eternals.sql(1 hunks)packages/db/migrations/meta/_journal.json(1 hunks)packages/db/src/schema.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/db/src/schema.ts
- packages/db/migrations/meta/_journal.json
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/gateway/src/chat/chat.tsapps/ui/src/components/dashboard/log-card.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
**/*.{ts,tsx,js,jsx}: Always use tabs for indentation
No unnecessary code comments
Files:
apps/gateway/src/chat/chat.tsapps/ui/src/components/dashboard/log-card.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
**/*.{ts,tsx}: Never useanyoras anyunless absolutely necessary in TypeScript code
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/gateway/src/chat/chat.tsapps/ui/src/components/dashboard/log-card.tsx
apps/{gateway,api}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Zod schemas for validation in Hono applications
Files:
apps/gateway/src/chat/chat.ts
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation in Next.js
Files:
apps/ui/src/components/dashboard/log-card.tsx
🧬 Code graph analysis (2)
apps/gateway/src/chat/chat.ts (1)
apps/gateway/src/lib/logs.ts (1)
calculateDataStorageCost(88-104)
apps/ui/src/components/dashboard/log-card.tsx (1)
packages/db/src/schema.ts (1)
log(378-480)
⏰ 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). (10)
- GitHub Check: autofix
- GitHub Check: test / run
- GitHub Check: build / run
- GitHub Check: e2e-shards (5)
- GitHub Check: lint / run
- GitHub Check: generate / run
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (3)
🔇 Additional comments (5)
apps/ui/src/components/dashboard/log-card.tsx (3)
12-12: LGTM!The Info icon import is necessary for the new retention tooltip feature.
704-713: LGTM!The conditional rendering for the Message Context section is implemented correctly. It clearly displays either the message data or an informative notice about retention settings.
741-750: LGTM!The Response section follows the same pattern as the Message Context section, providing consistent UX when displaying retention notices. The implementation correctly handles both the presence and absence of content.
apps/gateway/src/chat/chat.ts (2)
10-10: LGTM!The import follows the coding guidelines by using top-level imports.
2192-2192: LGTM!Setting
dataStorageCostto"0"in error and cancellation paths is correct since no data is stored in these cases.Also applies to: 2279-2279, 2429-2429, 3667-3667, 3751-3751, 3864-3864
- Change default retention level from "retain" to "none" for new organizations - Update Pro plan retention period from 7 to 30 days - Add dataStorageCost column to track storage costs separately - Implement $0.01 per 1M tokens billing for data storage (input + cached + output + reasoning) - Update activity API to aggregate data storage costs - Add UI messaging about retention periods and storage billing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Set retentionLevel to "retain" in api.spec.ts test setup to ensure content is stored and tests can verify log content. Required due to new default retention level being "none". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Make "Data storage is billed at $0.01 per 1M tokens" text bold for better visibility of the pricing information. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add tooltip icon in collapsed view when content is not retained - Show informative message in expanded view for missing response content - Add similar messaging for missing message context - Guide users to enable retention in organization policies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add Data Storage Cost field to Cost Information section - Change "Content not retained" placeholder to "---" for cleaner UI - Display storage cost with 8 decimal precision like other costs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
041baee to
2ba9960
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
packages/db/migrations/1764086480_flashy_salo.sql (1)
1-1: Specify precision for numeric cost column to avoid floating-point precision issues (unresolved from prior review).Cost and financial tracking requires fixed precision to prevent rounding errors. Additionally, the DEFAULT should use a numeric literal, not a string.
Apply this diff to fix the data type and default value:
-ALTER TABLE "log" ADD COLUMN "data_storage_cost" numeric DEFAULT '0' NOT NULL; +ALTER TABLE "log" ADD COLUMN "data_storage_cost" numeric(12, 4) DEFAULT 0 NOT NULL;
numeric(12, 4)provides 12 total digits with 4 decimal places, suitable for cost tracking at sub-cent precision while preventing unbounded scale growth.apps/ui/src/components/dashboard/log-card.tsx (1)
82-108: Retention tooltip wording is still inconsistent with “organization policies”.The new header logic and tooltip trigger look good, and the conditions for when to show the Info icon make sense. However, the tooltip text still says “Enable retention in project settings…”, while the Message Context/Response sections now refer to “organization policies”. This recreates the earlier inconsistency.
Recommend aligning the tooltip copy with the other sections:
- <TooltipContent> - <p> - Enable retention in project settings to store response - content - </p> - </TooltipContent> + <TooltipContent> + <p> + Enable retention in organization policies to store + response content. + </p> + </TooltipContent>
🧹 Nitpick comments (1)
apps/ui/src/components/dashboard/log-card.tsx (1)
399-404: Data Storage Cost display is wired correctly; consider numeric check for “0” default.Hooking
Data Storage Costtolog.dataStorageCostand formatting to 8 decimals matches the new billing requirement. One small nuance: because the DB default for a decimal is typically the string"0", this truthiness check will render$0.00000000instead of the plain$0used elsewhere when the cost is zero.If you prefer consistent
$0behavior for zero, you could gate on the numeric value instead:- <div> - {log.dataStorageCost - ? `$${Number(log.dataStorageCost).toFixed(8)}` - : "$0"} - </div> + <div> + {Number(log.dataStorageCost ?? 0) > 0 + ? `$${Number(log.dataStorageCost).toFixed(8)}` + : "$0"} + </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/ui/src/components/dashboard/log-card.tsx(5 hunks)packages/db/migrations/1764086480_flashy_salo.sql(1 hunks)packages/db/migrations/meta/_journal.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/db/migrations/meta/_journal.json
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/ui/src/components/dashboard/log-card.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
**/*.{ts,tsx,js,jsx}: Always use tabs for indentation
No unnecessary code comments
Files:
apps/ui/src/components/dashboard/log-card.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
**/*.{ts,tsx}: Never useanyoras anyunless absolutely necessary in TypeScript code
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation in Next.js
Files:
apps/ui/src/components/dashboard/log-card.tsx
🧬 Code graph analysis (1)
apps/ui/src/components/dashboard/log-card.tsx (1)
packages/db/src/schema.ts (1)
log(378-480)
🔇 Additional comments (4)
packages/db/migrations/1764086480_flashy_salo.sql (1)
2-2: Retention default change aligns with PR objectives.The change to default new organizations to
'none'retention level (metadata-only storage) matches the PR objective and enables the data storage billing feature.apps/ui/src/components/dashboard/log-card.tsx (3)
12-12: Info icon import is appropriate for the new retention tooltip.The
Infoicon import fromlucide-reactis used correctly for the new tooltip and follows the existing icon pattern in this component.
705-714: Message Context retention notice is clear and aligned with org-level policies.The conditional rendering of raw
log.messagesvs the “Message data not retained…” notice is correct and the copy explicitly points users to “Enable retention in organization policies…”, which matches the new default retention behavior.
742-751: Response retention notice cleanly explains missing content.The Response section’s conditional rendering works well: full content when present, and a concise explanation when not retained, again pointing to “organization policies” for enabling retention. This is consistent with the Message Context copy and supports the new metadata-only default.
- Add credit validation in gateway before processing requests when retention is enabled to prevent insufficient credit errors - Implement storage cost deduction in API keys mode (worker only deducts storage costs, not inference costs) - Separate storage costs from inference costs in dashboard UI to clearly distinguish provider costs from LLM Gateway costs - Update log card tooltip to use consistent "organization policies" terminology instead of "project settings" - Add auto top-up tip in retention settings with link to billing - Storage costs billed at $0.01 per 1M tokens for retained data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
apps/gateway/src/chat/chat.ts (1)
1836-1841: ReconfirmcalculateDataStorageCosttoken counting (cached_tokens subset) and usageAll the new log writes correctly surface
dataStorageCostby either setting"0"on error/canceled paths or calling:dataStorageCost: calculateDataStorageCost( promptTokensLike, cachedTokensLike, completionTokensLike, reasoningTokensLike, )However, previous review already noted that in OpenAI-style APIs
prompt_tokens_details.cached_tokensis a subset ofprompt_tokens, not additional tokens. IfcalculateDataStorageCostin@/lib/logs.tsstill sums all four parameters (prompt + cached + completion + reasoning), cached tokens will be double-counted in storage billing.Please verify that
calculateDataStorageCostnow computes something like:const totalTokens = prompt + completion + reasoning; // cached_tokens kept only for logging/analytics, not added againwith callers unchanged, so
cachedTokensremains available for logging but is not added to the token total.Also applies to: 1951-1955, 2203-2204, 2290-2291, 2440-2441, 3678-3678, 3762-3762, 3875-3875, 4112-4117
apps/ui/src/components/settings/organization-retention-settings.tsx (1)
147-178: Remove or clarify the non-existent Enterprise retention tierThe Alert lists
Enterprise plan: Unlimited, butorganization.planisz.enum(["free", "pro"])and there’s no enterprise tier or matching retention logic in the worker cleanup. This is misleading.Either drop the Enterprise line or clearly mark it as “coming soon” and keep only Free (3 days) and Pro (30 days) in the live UI.
🧹 Nitpick comments (2)
apps/worker/src/worker.ts (1)
56-75: Verify storage-cost deduction behavior for zero-cost logsThe wiring of
data_storage_costlooks consistent (schema, SELECT alias, and use inbatchProcessLogs), andPRO_PLAN_RETENTION_DAYS = 30matches the UI copy.One subtle behavior worth double-checking: storage-cost deduction is only executed inside
if (row.cost && row.cost > 0 && !row.cached) { … } else if (row.used_mode === "api-keys" && row.data_storage_cost) { const storageCost = new Decimal(row.data_storage_cost); … } }So for logs where
costis0(e.g. free/fully-discounted models) butdata_storage_cost > 0, no organization credits will ever be deducted for storage, even though tokens were logged.If the intent is “$0.01 per 1M tokens stored” regardless of compute cost, consider separating storage-cost deduction from the
row.cost > 0guard, e.g.:- if (row.cost && row.cost > 0 && !row.cached) { - // existing API-key usage + orgCost logic (credits mode uses row.cost) - … - } else if (row.used_mode === "api-keys" && row.data_storage_cost) { - … - } - } + // 1) Always account for storage cost when present (and not cached) + if (!row.cached && row.used_mode === "api-keys" && row.data_storage_cost) { + const storageCost = new Decimal(row.data_storage_cost); + if (storageCost.greaterThan(0)) { + const currentOrgCost = orgCosts.get(row.organization_id) || new Decimal(0); + orgCosts.set(row.organization_id, currentOrgCost.plus(storageCost)); + } + } + + // 2) Keep existing credit deduction & API-key usage gated on row.cost > 0 + if (row.cost && row.cost > 0 && !row.cached) { + // API-key usage update + credits-mode orgCosts based on row.cost + … + }Please adjust the separation/ordering as needed to match your billing model.
Also applies to: 340-342, 518-541, 590-621
apps/gateway/src/chat/chat.ts (1)
1614-1623: Consider scoping data-retention credit checks to hosted/paid deploymentsThe new guard:
if (organization && organization.retentionLevel === "retain") { if (parseFloat(organization.credits || "0") <= 0) { throw new HTTPException(402, { … }); } }will 402 any org with
retentionLevel === "retain"and zero credits, regardless ofHOSTED/PAID_MODE. That enforces storage billing even for self-hosted installs that may not use the credits system.If retention-based billing is only meant for the hosted/paid offering (similar to the custom-headers and API-keys-mode checks), consider wrapping this in the same
isHosted && isPaidModecondition, or documenting that self-hosted users must provision credits when enabling retention.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/gateway/src/chat/chat.ts(12 hunks)apps/ui/src/components/dashboard/dashboard-client.tsx(3 hunks)apps/ui/src/components/dashboard/log-card.tsx(5 hunks)apps/ui/src/components/settings/organization-retention-settings.tsx(2 hunks)apps/worker/src/worker.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/ui/src/components/dashboard/dashboard-client.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/worker/src/worker.tsapps/ui/src/components/dashboard/log-card.tsxapps/gateway/src/chat/chat.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
**/*.{ts,tsx,js,jsx}: Always use tabs for indentation
No unnecessary code comments
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/worker/src/worker.tsapps/ui/src/components/dashboard/log-card.tsxapps/gateway/src/chat/chat.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
**/*.{ts,tsx}: Never useanyoras anyunless absolutely necessary in TypeScript code
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/worker/src/worker.tsapps/ui/src/components/dashboard/log-card.tsxapps/gateway/src/chat/chat.ts
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation in Next.js
Files:
apps/ui/src/components/settings/organization-retention-settings.tsxapps/ui/src/components/dashboard/log-card.tsx
apps/{gateway,api}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Zod schemas for validation in Hono applications
Files:
apps/gateway/src/chat/chat.ts
🧠 Learnings (4)
📚 Learning: 2025-11-25T14:31:41.560Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T14:31:41.560Z
Learning: Applies to apps/{ui,playground}/src/**/*.{ts,tsx} : Use `next/link` for links and `next/navigation`'s router for programmatic navigation in Next.js
Applied to files:
apps/ui/src/components/settings/organization-retention-settings.tsx
📚 Learning: 2025-11-24T20:02:21.810Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T20:02:21.810Z
Learning: Applies to apps/ui/**/*.{ts,tsx} : Use Next.js App Router with React Server Components for frontend development
Applied to files:
apps/ui/src/components/settings/organization-retention-settings.tsx
📚 Learning: 2025-11-24T20:02:21.810Z
Learnt from: CR
Repo: theopenco/llmgateway PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T20:02:21.810Z
Learning: Applies to apps/{ui,playground}/**/*.{ts,tsx} : Use `next/link` for links and `next/navigation`'s router for programmatic navigation
Applied to files:
apps/ui/src/components/settings/organization-retention-settings.tsx
📚 Learning: 2025-08-04T21:46:14.112Z
Learnt from: mowdl
Repo: theopenco/llmgateway PR: 572
File: apps/gateway/src/worker.ts:292-298
Timestamp: 2025-08-04T21:46:14.112Z
Learning: In the LLMGateway system, API key usage should be tracked for all keys regardless of project billing mode. This dual tracking approach allows credit deduction for non-"api-keys" mode projects while maintaining comprehensive usage statistics across all API keys for monitoring and analytics purposes.
Applied to files:
apps/worker/src/worker.ts
🧬 Code graph analysis (3)
apps/worker/src/worker.ts (1)
packages/db/src/schema.ts (1)
log(378-480)
apps/ui/src/components/dashboard/log-card.tsx (1)
packages/db/src/schema.ts (1)
log(378-480)
apps/gateway/src/chat/chat.ts (2)
packages/db/src/schema.ts (1)
organization(109-147)apps/gateway/src/lib/logs.ts (1)
calculateDataStorageCost(88-104)
⏰ 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). (10)
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (3)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (5)
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: build / run
- GitHub Check: autofix
- GitHub Check: test / run
🔇 Additional comments (4)
apps/ui/src/components/dashboard/log-card.tsx (4)
12-12: LGTM!The
Infoicon import supports the new retention tooltip feature.
82-108: LGTM! Terminology now consistent.The content display logic correctly handles tool calls, errors, and missing content scenarios. The retention tooltip now consistently uses "organization policies" terminology, addressing the previous review comment.
399-411: LGTM!The cost breakdown now clearly separates inference costs from gateway costs. The "Inference Total" label clarifies the scope of
log.cost, and the data storage cost is displayed consistently with other cost fields.
708-717: LGTM!The retention messaging in both Message Context and Response sections is clear and actionable. The conditional rendering properly distinguishes between request messages and response content, guiding users to enable retention in organization policies.
Also applies to: 745-754
- Add LLM Gateway Storage as separate item in cost breakdown chart when storage costs exist (shown in indigo color) - Update cost breakdown documentation with storage cost field - Add detailed data storage costs section in documentation - Clarify that cost_usd_total excludes storage costs (inference only) - Document storage billing: $0.01 per 1M tokens when retention enabled 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix failing unit tests by adding credits to test organization - Tests were failing with 402 status because credit check blocks requests when retention is enabled but credits are zero - Add 100.00 credits to test organization in gateway api.spec.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/docs/content/features/cost-breakdown.mdx(2 hunks)apps/gateway/src/api.spec.ts(1 hunks)apps/gateway/src/chat/chat.ts(12 hunks)apps/ui/src/components/usage/cost-breakdown-chart.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/gateway/src/api.spec.ts
- apps/gateway/src/chat/chat.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
**/*.{ts,tsx,js,jsx}: Always use tabs for indentation
No unnecessary code comments
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
**/*.{ts,tsx}: Never useanyoras anyunless absolutely necessary in TypeScript code
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation in Next.js
Files:
apps/ui/src/components/usage/cost-breakdown-chart.tsx
⏰ 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). (10)
- GitHub Check: test / run
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (5)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (3)
- GitHub Check: autofix
🔇 Additional comments (2)
apps/ui/src/components/usage/cost-breakdown-chart.tsx (1)
138-145: LGTM! Storage cost visualization implemented correctly.The conditional logic properly adds storage costs as a separate chart entry only when costs exist, preventing empty slices. The fixed indigo color provides clear visual distinction from provider costs.
apps/docs/content/features/cost-breakdown.mdx (1)
216-230: LGTM! Clear and comprehensive storage cost documentation.The Data Storage Costs section effectively explains the pricing model, applicability conditions, and billing behavior. The callout about auto top-up is a helpful user-facing tip.
- Update plan management UI: 90-day → 30-day retention - Update pricing plans page: 90-day → 30-day retention - Update gateway v1 launch changelog: 90-day → 30-day retention - Align marketing materials with actual Pro plan retention period 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/ui/src/content/changelog/2025-05-01-gateway-v1-launch.md (1)
92-92: Clarify retention tier messaging.Line 92 mentions "30-day retention" in the general Comprehensive Analytics section without explicitly tying it to the Pro plan, whereas line 160 explicitly states "3-day data retention" for the free tier. This creates ambiguity about which tier offers which retention period.
Given the PR objectives specify Pro plan retention was updated to 30 days, consider either:
- Moving this statement to the "Pro Plan Features" section (line 112+) and qualifying it as Pro-specific, or
- Reword to explicitly indicate tier-based retention (e.g., "up to 30-day retention (Pro plan)").
This ensures clarity for readers about retention capabilities by plan.
apps/ui/src/components/billing/plan-management.tsx (1)
185-203: Copy update matches 30‑day retention; consider clarifying Pro specificityThe change to “30-day data retention” aligns with the new 30‑day retention policy. Since this section is shown for both Free and Pro, you might optionally clarify that 30‑day retention is a Pro benefit to avoid confusion for Free orgs (whose default is metadata-only).
Example tweak (no logic change, just copy):
- <span>30-day data retention</span> + <span>Up to 30-day data retention (Pro)</span>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/ui/src/components/billing/plan-management.tsx(1 hunks)apps/ui/src/components/landing/pricing-plans.tsx(1 hunks)apps/ui/src/content/changelog/2025-05-01-gateway-v1-launch.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Always use top-levelimport, never use require or dynamic imports
No unnecessary code comments
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use cookies for user-settings which are not saved in the database to ensure SSR works
**/*.{ts,tsx,js,jsx}: Always use tabs for indentation
No unnecessary code comments
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
**/*.{ts,tsx}: Never useanyoras anyunless absolutely necessary in TypeScript code
Always use top-levelimport, never use require or dynamic imports
Use cookies for user-settings which are not saved in the database to ensure SSR works
Use Drizzle ORM with latest object syntax for database operations
For database reads: Usedb().query.<table>.findMany()ordb().query.<table>.findFirst()
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Next.js App Router with React Server Components for frontend development
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
apps/{ui,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
next/linkfor links andnext/navigation's router for programmatic navigation in Next.js
Files:
apps/ui/src/components/landing/pricing-plans.tsxapps/ui/src/components/billing/plan-management.tsx
⏰ 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). (10)
- GitHub Check: autofix
- GitHub Check: build / run
- GitHub Check: test / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: e2e-shards (4)
- GitHub Check: e2e-shards (1)
- GitHub Check: e2e-shards (5)
- GitHub Check: e2e-shards (2)
- GitHub Check: e2e-shards (3)
🔇 Additional comments (1)
apps/ui/src/components/landing/pricing-plans.tsx (1)
225-234: Pro plan copy updated to 30‑day retention – verify consistency across systemThe updated feature string
"30-day data retention"for the Pro plan matches the PR objective (Pro retention → 30 days) and looks good from a UI/copy perspective. Please double-check that:
- The actual Pro retention configuration in the backend is 30 days, and
- Other UI surfaces/docs describing Pro retention have been updated to the same value,
to avoid user-facing inconsistencies.
- Fix cost_usd_data_storage from 0.00025 to 0.00000025 - Calculation: 25 tokens × ($0.01 / 1,000,000) = $0.00000025 - Ensures example accurately reflects the documented rate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Change totalStorageCost += day.dataStorageCost to use Number() || 0 - Prevents NaN when dataStorageCost is undefined or non-numeric - Ensures cost breakdown chart displays correctly for all data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Summary
dataStorageCostcolumn and calculation: $0.01 per 1M tokens (input + cached + output + reasoning)Test plan
dataStorageCostfield🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.