Skip to content

feat: default retention to metadata-only, add data storage billing - #1243

Merged
steebchen merged 15 commits into
mainfrom
retention-none-default
Nov 26, 2025
Merged

steebchen merged 15 commits into
mainfrom
retention-none-default

Conversation

@steebchen

@steebchen steebchen commented Nov 25, 2025 •

Copy link
Copy Markdown
Member

Summary

  • Default retention level changed from "retain" to "none" for new organizations, ensuring metadata-only storage by default
  • Pro plan retention period updated from 7 to 30 days to match marketing claims
  • Added dataStorageCost column and calculation: $0.01 per 1M tokens (input + cached + output + reasoning)
  • Activity API now aggregates and returns data storage costs separately for billing insights
  • UI messaging added to inform users about retention periods and storage billing costs

Test plan

  • Verify new organizations default to "none" retention level
  • Check that data storage costs are calculated correctly in logs
  • Confirm activity endpoint returns dataStorageCost field
  • Test dashboard displays storage costs in cost breakdown

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Data storage costs are tracked and shown across activity summaries, cost breakdown charts, dashboard, and log cards (new "Data Storage" line; "Inference Cost" header).
    • Settings UI now surfaces retention options with pricing details and plan-based retention periods.
  • Documentation

    • Added Data Storage Costs section, examples, and clarifications in usage docs.
  • Chores

    • Pro plan retention standardized to 30 days; default retention behavior updated.

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

@coderabbitai

coderabbitai Bot commented Nov 25, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds end-to-end per-request data storage cost: DB column and migration, gateway utility to compute and include dataStorageCost in logs, propagation through worker processing and adjusted credit deduction rules, daily aggregation and API/schema exposure, and UI type and display updates.

Changes

Cohort / File(s) Summary
Database schema & migrations
packages/db/src/schema.ts, packages/db/migrations/1764086480_flashy_salo.sql, packages/db/migrations/meta/_journal.json
Add data_storage_cost / dataStorageCost column to log (numeric/decimal, NOT NULL, DEFAULT '0'); change organization retention_level default to "none"; add migration journal entry.
Gateway logging utility & usage
apps/gateway/src/lib/logs.ts, apps/gateway/src/chat/chat.ts
Add exported calculateDataStorageCost(...) (sums token counts, /1_000_000 * 0.01, returns string); call it across normal, cached, streaming, non-streaming and error logging paths; include dataStorageCost in log payloads and add a retention/credits pre-check.
Worker processing & retention
apps/worker/src/worker.ts
Include data_storage_cost in processing schema and propagated rows; adjust credit deduction so api-keys mode may deduct only storage cost when present; increase PRO_PLAN_RETENTION_DAYS from 7 → 30; update related logging.
API activity aggregation
apps/api/src/routes/activity.ts
Extend daily aggregates to compute dataStorageCost via COALESCE(SUM(...), 0), parse day.dataStorageCost, and include in returned daily activity objects and dailyActivitySchema.
UI types, dashboard & log card
apps/ui/src/types/activity.ts, apps/ui/src/components/dashboard/dashboard-client.tsx, apps/ui/src/components/dashboard/log-card.tsx, apps/ui/src/components/usage/cost-breakdown-chart.tsx
Add dataStorageCost (and requestCost) to activity types; compute totalDataStorageCost; rename cost headers to "Inference Cost"/"Inference Total"; display per-log and dashboard storage cost lines and chart slice when > 0; show retention guidance when content missing.
Retention settings & plan copy
apps/ui/src/components/settings/organization-retention-settings.tsx, apps/ui/src/components/billing/plan-management.tsx, apps/ui/src/components/landing/pricing-plans.tsx, apps/ui/src/content/changelog/2025-05-01-gateway-v1-launch.md
Add retention info block and pricing ($0.01 per 1M tokens) when retention is enabled; update Pro plan retention copy from 90 → 30 days and changelog/plan UI copy.
Tests
apps/gateway/src/api.spec.ts
Test fixture updated: organization insert includes retentionLevel: "retain" and credits: "100.00".
Docs
apps/docs/content/features/cost-breakdown.mdx
Add cost_usd_data_storage example, document Data Storage Costs section, update cost fields table and callouts to clarify storage is billed separately.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • Verify numeric formula, precision and choice to return storage cost as string vs numeric across layers.
    • Confirm consistent naming/mapping between data_storage_cost (DB) and dataStorageCost (JS/TS) in queries, migrations, worker, and API schema.
    • Ensure all logging paths (streaming, cached, non-streaming, and error) consistently set dataStorageCost.
    • Review worker credit-deduction changes for api-keys vs credits modes to avoid billing regressions.
    • Check UI formatting and zod/schema consistency for the new fields.

Possibly related PRs

Suggested reviewers

  • smakosh

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: setting default retention to metadata-only and introducing data storage billing functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch retention-none-default

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25096c6 and 5931969.

📒 Files selected for processing (2)
  • apps/docs/content/features/cost-breakdown.mdx (2 hunks)
  • apps/ui/src/components/usage/cost-breakdown-chart.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().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/link for links and next/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/link for links and next/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). (8)
  • GitHub Check: e2e-shards (2)
  • GitHub Check: e2e-shards (4)
  • GitHub Check: e2e-shards (5)
  • GitHub Check: e2e-shards (3)
  • GitHub Check: e2e-shards (1)
  • GitHub Check: build / run
  • GitHub Check: test / run
  • GitHub Check: autofix
🔇 Additional comments (7)
apps/ui/src/components/usage/cost-breakdown-chart.tsx (3)

120-120: LGTM!

The initialization of totalStorageCost is correct and follows the established pattern for cost tracking in this component.


127-127: LGTM!

The storage cost accumulation correctly handles undefined/null values using Number() || 0. While the past review suggested ?? 0, both approaches safely handle missing data and produce the correct result.


138-145: LGTM!

The conditional addition of storage cost to the chart data is well-implemented. The check prevents empty entries, the naming is clear, and the distinct color effectively differentiates storage costs from provider costs.

apps/docs/content/features/cost-breakdown.mdx (4)

47-47: LGTM!

The cost_usd_data_storage example value of 0.00000025 is mathematically correct: 25 tokens × ($0.01 / 1,000,000) = $0.00000025. The past calculation error has been properly addressed.


54-62: LGTM!

The cost fields table accurately documents the new cost_usd_data_storage field with the correct rate and clearly explains when it applies. The clarification that cost_usd_total excludes storage is an important addition.


63-67: LGTM!

The callout provides crucial clarification about cost separation, preventing potential user confusion about why storage costs aren't included in cost_usd_total. The explanation is clear and accurate.


216-230: LGTM!

The "Data Storage Costs" section comprehensively documents the new billing feature. The rate ($0.01 per 1M tokens), applicable token types, and retention conditions are all accurate and align with the PR objectives. The auto top-up callout is a helpful UX touch.

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.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (4)
apps/ui/src/components/settings/organization-retention-settings.tsx (2)

27-29: Sync retentionLevel with selectedOrganization and default to "none"

retentionLevel is initialized once from selectedOrganization?.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.useEffect that resets retentionLevel whenever selectedOrganization.id / retentionLevel changes so the form always reflects the active org.

145-162: Alert copy matches behavior but duplicates retention/pricing constants

The 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:

  • cleanupExpiredLogData in apps/worker/src/worker.ts (3/30‑day retention).
  • calculateDataStorageCost in apps/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 friendliness

The implementation correctly computes storage cost as $0.01 / 1M over 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 token

This 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 calculation

For both:

  • Streaming success logs (around 3448–3453), and
  • Non‑streaming success logs (around 4045–4050),

dataStorageCost is 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: calculateCosts in nearby code still uses the raw reasoningTokens variable in some paths, while storage cost uses calculatedReasoningTokens. If you eventually want compute and storage to be based on the same token estimates, you could pass the calculated reasoning tokens into calculateCosts as well.

Also applies to: 4045-4050

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db8a119 and e493a59.

⛔ Files ignored due to path filters (2)
  • apps/playground/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/ui/src/lib/api/v1.d.ts is 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 use any or as any type assertions unless absolutely necessary
Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • apps/gateway/src/lib/logs.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/api/src/routes/activity.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/chat/chat.ts
  • apps/ui/src/types/activity.ts
  • packages/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 services

Use Zod schemas for validation in Hono applications

Files:

  • apps/gateway/src/lib/logs.ts
  • apps/api/src/routes/activity.ts
  • apps/gateway/src/chat/chat.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Always use top-level import, never use require or dynamic imports
No unnecessary code comments

Files:

  • apps/gateway/src/lib/logs.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/api/src/routes/activity.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/chat/chat.ts
  • apps/ui/src/types/activity.ts
  • packages/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.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/api/src/routes/activity.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/chat/chat.ts
  • apps/ui/src/types/activity.ts
  • packages/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
Use next/link for links and next/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applications

Use next/link for links and next/navigation's router for programmatic navigation

Files:

  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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.tsx
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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, use db().query.<table>.findMany() or db().query.<table>.findFirst()
For database schema changes, use pnpm run setup instead of writing migrations which will generate .sql files
Always sync schema with pnpm run setup after 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 intended

The PRO_PLAN_RETENTION_DAYS constant 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.retentionLevel now defaulting to "none" matches the new default-retention behavior for orgs.
  • log.dataStorageCost as decimal().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 /db modules.

Also applies to: 461-462

apps/ui/src/components/dashboard/dashboard-client.tsx (1)

89-103: Cost breakdown now includes storage; verify it matches what cost represents

The new aggregations for totalRequestCost and totalDataStorageCost, 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 thus totalCost) is defined as:

inputCost + outputCost + requestCost + dataStorageCost

If cost excludes 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 fields

Extending DailyActivity and ActivitT with requestCost and dataStorageCost keeps the UI types aligned with dailyActivitySchema and 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 API

Including dataStorageCost in the Zod schema, SQL aggregation (COALESCE(SUM(log.dataStorageCost), 0)), and the mapped activityData objects 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 calculateDataStorageCost

Importing calculateDataStorageCost alongside insertLog ensures all log callers use the same pricing logic for storage, rather than duplicating the $0.01 / 1M tokens formula in multiple places.


1745-1775: Cached responses correctly account for storage cost

For both:

  • Cached streaming responses (lines around 1813–1818), and
  • Cached non‑streaming responses (lines around 1926–1931),

you compute dataStorageCost from the appropriate promptTokens, cachedTokens, completionTokens, and reasoningTokens. 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 default

In 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (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 on Number(...) || 0 to hide NaN.
  • Round to a fixed precision (e.g., toFixed(8)) if you want consistent decimals rather than possible exponential notation from toString().

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, reasoningTokens from the reconstructed usage.
  • Cached non‑streaming: uses cachedResponse.usage fields.
  • 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, and reasoningTokens. One small follow‑up you might consider later: calculateCosts still uses the original reasoningTokens variable, whereas dataStorageCost (and the logged reasoningTokens field) now use calculatedReasoningTokens; 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), dataStorageCost is hard‑coded to "0", while successful flows use calculateDataStorageCost(...). 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 calculateDataStorageCost here 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

📥 Commits

Reviewing files that changed from the base of the PR and between db8a119 and c680428.

⛔ Files ignored due to path filters (2)
  • apps/playground/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/ui/src/lib/api/v1.d.ts is 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 use any or as any type assertions unless absolutely necessary
Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • packages/db/src/schema.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/lib/logs.ts
  • apps/ui/src/types/activity.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/api/src/routes/activity.ts
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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, use db().query.<table>.findMany() or db().query.<table>.findFirst()
For database schema changes, use pnpm run setup instead of writing migrations which will generate .sql files
Always sync schema with pnpm run setup after 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-level import, never use require or dynamic imports
No unnecessary code comments

Files:

  • packages/db/src/schema.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/lib/logs.ts
  • apps/ui/src/types/activity.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/api/src/routes/activity.ts
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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.ts
  • apps/worker/src/worker.ts
  • apps/gateway/src/lib/logs.ts
  • apps/ui/src/types/activity.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/api/src/routes/activity.ts
  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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 services

Use Zod schemas for validation in Hono applications

Files:

  • apps/gateway/src/lib/logs.ts
  • apps/api/src/routes/activity.ts
  • apps/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
Use next/link for links and next/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applications

Use next/link for links and next/navigation's router for programmatic navigation

Files:

  • apps/ui/src/types/activity.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/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.ts
  • apps/ui/src/components/dashboard/dashboard-client.tsx
  • apps/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 setup to sync the schema changes.


461-461: LGTM! Data storage cost column added safely.

The new dataStorageCost column 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 setup to 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_cost column with a safe default value for existing rows
  • Updates the retention_level default to 'none' for new organizations

Both 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 dataStorageCost field 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 with COALESCE.

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 requestCost and dataStorageCost to both DailyActivity and ActivitT, aligning with the API response schema changes in apps/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 totalDataStorageCost by aggregating from activity data (lines 100-101)
  • Simplify totalRequestCost to 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 calculateDataStorageCost here centralizes the storage‑billing logic and keeps the chat route free of hard‑coded pricing constants, which will make future pricing changes easier.

Comment thread apps/ui/src/components/settings/organization-retention-settings.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e493a59 and e6cae88.

📒 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 use any or as any type assertions unless absolutely necessary
Always use top-level import, 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: Use db().query.<table>.findMany() or db().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 services

Use 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-level import, 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_level changes 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_level handles '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 checks logs[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 in packages/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.

Comment thread packages/db/migrations/1764086480_flashy_salo.sql

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6cae88 and 1065755.

📒 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 use any or as any type assertions unless absolutely necessary
Always use top-level import, 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: Use db().query.<table>.findMany() or db().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
Use next/link for links and next/navigation's router for programmatic navigation in Next.js applications
Use TanStack Query for state management in frontend applications

Use next/link for links and next/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-level import, 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 Info icon 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.

Comment thread apps/ui/src/components/dashboard/log-card.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/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 NULL for financial data precision hasn't been addressed. The column still uses unbounded numeric with 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1065755 and 24d4661.

📒 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-level import, never use require or dynamic imports
No unnecessary code comments

Files:

  • apps/gateway/src/chat/chat.ts
  • 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/gateway/src/chat/chat.ts
  • 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • apps/gateway/src/chat/chat.ts
  • apps/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/link for links and next/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/link for links and next/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 dataStorageCost to "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

Comment thread apps/gateway/src/chat/chat.ts
steebchen and others added 8 commits November 26, 2025 00:06
- 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>
@steebchen
steebchen force-pushed the retention-none-default branch from 041baee to 2ba9960 Compare November 25, 2025 16:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 Cost to log.dataStorageCost and 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.00000000 instead of the plain $0 used elsewhere when the cost is zero.

If you prefer consistent $0 behavior 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

📥 Commits

Reviewing files that changed from the base of the PR and between 24d4661 and 041baee.

📒 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-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().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/link for links and next/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/link for links and next/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 Info icon import from lucide-react is 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.messages vs 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>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/gateway/src/chat/chat.ts (1)

1836-1841: Reconfirm calculateDataStorageCost token counting (cached_tokens subset) and usage

All the new log writes correctly surface dataStorageCost by 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_tokens is a subset of prompt_tokens, not additional tokens. If calculateDataStorageCost in @/lib/logs.ts still sums all four parameters (prompt + cached + completion + reasoning), cached tokens will be double-counted in storage billing.

Please verify that calculateDataStorageCost now computes something like:

const totalTokens = prompt + completion + reasoning;
// cached_tokens kept only for logging/analytics, not added again

with callers unchanged, so cachedTokens remains 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 tier

The Alert lists Enterprise plan: Unlimited, but organization.plan is z.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 logs

The wiring of data_storage_cost looks consistent (schema, SELECT alias, and use in batchProcessLogs), and PRO_PLAN_RETENTION_DAYS = 30 matches 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 cost is 0 (e.g. free/fully-discounted models) but data_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 > 0 guard, 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 deployments

The 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 of HOSTED / 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 && isPaidMode condition, or documenting that self-hosted users must provision credits when enabling retention.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ba9960 and 67e53c2.

📒 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-level import, never use require or dynamic imports
No unnecessary code comments

Files:

  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/worker/src/worker.ts
  • apps/ui/src/components/dashboard/log-card.tsx
  • apps/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.tsx
  • apps/worker/src/worker.ts
  • apps/ui/src/components/dashboard/log-card.tsx
  • apps/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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/worker/src/worker.ts
  • apps/ui/src/components/dashboard/log-card.tsx
  • 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/settings/organization-retention-settings.tsx
  • apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use next/link for links and next/navigation's router for programmatic navigation

Files:

  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/ui/src/components/dashboard/log-card.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use next/link for links and next/navigation's router for programmatic navigation in Next.js

Files:

  • apps/ui/src/components/settings/organization-retention-settings.tsx
  • apps/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 Info icon 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

steebchen and others added 3 commits November 26, 2025 15:53
- 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>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67e53c2 and 5b34115.

📒 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-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().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/link for links and next/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/link for links and next/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.

Comment thread apps/docs/content/features/cost-breakdown.mdx Outdated
Comment thread apps/ui/src/components/usage/cost-breakdown-chart.tsx Outdated
- 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>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (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:

  1. Moving this statement to the "Pro Plan Features" section (line 112+) and qualifying it as Pro-specific, or
  2. 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 specificity

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between 5b34115 and 25096c6.

📒 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-level import, never use require or dynamic imports
No unnecessary code comments

Files:

  • apps/ui/src/components/landing/pricing-plans.tsx
  • apps/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.tsx
  • apps/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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

**/*.{ts,tsx}: Never use any or as any unless absolutely necessary in TypeScript code
Always use top-level import, 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: Use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • apps/ui/src/components/landing/pricing-plans.tsx
  • apps/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.tsx
  • apps/ui/src/components/billing/plan-management.tsx
apps/{ui,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use next/link for links and next/navigation's router for programmatic navigation

Files:

  • apps/ui/src/components/landing/pricing-plans.tsx
  • apps/ui/src/components/billing/plan-management.tsx
apps/{ui,playground}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use next/link for links and next/navigation's router for programmatic navigation in Next.js

Files:

  • apps/ui/src/components/landing/pricing-plans.tsx
  • apps/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 system

The 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.

steebchen and others added 2 commits November 26, 2025 18:41
- 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>
@steebchen
steebchen added this pull request to the merge queue Nov 26, 2025
Merged via the queue into main with commit 72e6951 Nov 26, 2025
13 checks passed
@steebchen
steebchen deleted the retention-none-default branch November 26, 2025 10:52
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