Skip to content

feat: add top_up workflow with Stripe#1238

Merged
riderx merged 121 commits intomainfrom
credits-top-up-dashboard
Dec 12, 2025
Merged

feat: add top_up workflow with Stripe#1238
riderx merged 121 commits intomainfrom
credits-top-up-dashboard

Conversation

@Dalanir
Copy link
Copy Markdown
Contributor

@Dalanir Dalanir commented Oct 29, 2025

Summary

  • Add a way to buy credits through Stripe and visualize our credits usage in a dedicated page, into Organization's settings.

Test plan

Quiet complex

  • you have to create a test environment in Stripe
  • Create the product into it
  • Create the customer
  • Change the product_id into the "credits.ts"
  • Link the customer_id from stripe to your current logged user
  • Click on "buy credits" in the Credits tab

Screenshots

Capture d’écran 2025-11-04 à 17 18 41 Capture d’écran 2025-11-04 à 17 18 54

Checklist

  • My code follows the code style of this project and passes
    bun run lint:backend && bun run lint.
  • My change requires a change to the documentation.
  • I have updated the documentation
    accordingly.
  • My change has adequate E2E test coverage.
  • I have tested my code manually, and I have provided steps how to reproduce
    my tests

Summary by CodeRabbit

  • New Features
    • Full credits system: balance, usage, expiration, pricing tiers, top‑up flow with Stripe checkout, daily‑aggregated transactions, alerts, and a new Credits settings page/tab.
  • Localization
    • Expanded translations for credits, pricing and plan UI across multiple languages.
  • Bug Fixes
    • Standardized icon assets and minor UI layout refinements.
  • Chores
    • Database schema, seed data and tests updated to support credits/ledger and top‑up flows; removed legacy feature flag.

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

@Dalanir Dalanir self-assigned this Oct 29, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 29, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a full credits system: translations across locales, DB schema/migration/types for credit grants/ledger/alerts, Supabase functions and Stripe checkout helpers, frontend Credits page with routing/tab, service APIs/types, tests, seeds, and removes legacy FEATURE_CREDITS_V2 and dashboard credits panel.

Changes

Cohort / File(s) Summary
Translations (multi-language)
messages/*.json (e.g., messages/en.json, messages/de.json, messages/fr.json, messages/es.json, messages/ja.json, messages/zh-cn.json, messages/pt-br.json, messages/ko.json, messages/it.json, messages/id.json, messages/hi.json, messages/ru.json, messages/tr.json, messages/vi.json, messages/pl.json)
Added extensive credits-related translation keys (credit-transaction-, credits-, credits-pricing-, credits-top-up-, buy-credits, plan keys); minor reordering, typo fixes, and occasional removals/relocations.
Database migration & seed
supabase/migrations/20251125184322_add_top_up_credits_system.sql, supabase/seed.sql
Adds plans.credit_id (default/NOT NULL), capgo_credit_products, usage_credit_alert_state, usage_credit_ledger view, unique guards/indexes, full top_up_usage_credits implementation, alert triggers/cron helpers, and updated seed data for plans/grants/transactions.
Database types
src/types/supabase.types.ts, supabase/functions/_backend/utils/supabase.types.ts
Exposes plans.credit_id, new usage_credit_ledger table/view types, and top_up_usage_credits function signature.
Supabase functions & Stripe utils
supabase/functions/_backend/private/credits.ts, supabase/functions/_backend/utils/stripe.ts, supabase/functions/_backend/utils/hono_middleware_stripe.ts
New endpoints /start-top-up and /complete-top-up, org↔Stripe context resolution, one-time checkout creation, session verification, idempotency checks, and environment resolution helpers.
Alert trigger & registration
supabase/functions/_backend/triggers/credit_usage_alerts.ts, supabase/functions/triggers/index.ts
New HTTP handler for credit usage alerts that maps thresholds to events, sends notifications/logs, and registers the trigger route.
Frontend — Credits UI & routing
src/pages/settings/organization/Credits.vue, src/typed-router.d.ts, src/constants/organizationTabs.ts, src/layouts/settings.vue
New Credits.vue page (balance, pricing, top-up flow, transactions, checkout handling), route and tab registration, and dynamic settings tab visibility based on permissions.
Frontend — Usage / Plans / Dashboard updates
src/pages/settings/organization/Usage.vue, src/pages/settings/organization/Plans.vue, src/components/dashboard/Usage.vue
Integrated usage credit deductions into Usage pricing; simplified Plans pricing conditionals; removed creditsV2 flag and deleted the dashboard credits panel.
Service layer & types
src/services/stripe.ts, src/services/supabase.ts, src/auto-imports.d.ts
Added startCreditTopUp and completeCreditTopUp, getUsageCreditDeductions and UsageCreditLedgerRow type, and resolveUnref auto-import typing.
Icon imports / asset changes
src/pages/settings/organization/Members.vue, src/pages/settings/organization/index.vue, src/pages/settings/account/ChangePassword.vue, src/pages/settings/account/index.vue
Replaced various icon imports with Heroicons equivalents.
Tests
supabase/tests/32_test_usage_credits.sql, supabase/tests/33_credit_usage_alerts.sql, supabase/tests/26_test_rls_policies.sql, tests/trigger-error-cases.test.ts, supabase/tests/00-supabase_test_helpers.sql
Expanded SQL tests for usage credits (idempotency, concurrency, ledger aggregation), new credit alert tests, added RLS/view checks, and adjusted webhook error expectation and test helper syntax.
Config / env / tooling
configs.json, README.md, vite.config.mts, supabase/functions/.env
Removed feature_credits_v2 config and VITE define, updated README, enabled STRIPE_SECRET_KEY in function env, changed WEBAPP_URL for local testing.
Misc / small fixes
supabase/functions/_backend/utils/stripe.ts (helper), supabase/functions/_backend/utils/hono_middleware_stripe.ts (whitespace), small icon/import tweaks
Minor helper additions, formatting fixes, and small import/whitespace tweaks.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant Frontend as Web UI (Credits.vue)
    participant API_Start as App Function (/start-top-up)
    participant Stripe
    participant API_Complete as App Function (/complete-top-up)
    participant DB as Supabase DB / RPC

    User->>Frontend: Click "Top up" (orgId, quantity)
    Frontend->>API_Start: POST /start-top-up (orgId, qty)
    API_Start->>API_Start: resolveOrgStripeContext (auth, customerId)
    API_Start->>Stripe: createOneTimeCheckout(productId, qty, successUrl)
    Stripe-->>API_Start: session.url
    API_Start-->>Frontend: return session URL
    Frontend->>Stripe: Redirect user to Checkout
    Stripe-->>Frontend: Redirect to successUrl?session_id=...
    Frontend->>API_Complete: POST /complete-top-up (orgId, sessionId)
    API_Complete->>Stripe: verify session, fetch line items
    API_Complete->>DB: RPC top_up_usage_credits(p_org_id, amount, session/payment refs)
    DB-->>API_Complete: grant/transaction info
    API_Complete-->>Frontend: return grant and new balances
    Frontend->>User: Show success and refresh organization state
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

  • Areas needing focused review:
    • Migration SQL and new functions: concurrency, idempotency, SECURITY DEFINER, RLS, triggers, and cron/task orchestration.
    • top_up_usage_credits(), usage_credit_ledger view, and alert handling: correctness of aggregation and edge cases.
    • Supabase ↔ Stripe integration: product/price lookup, environment resolution, checkout creation, session verification, and idempotency keys.
    • Frontend Credits.vue: daily ledger aggregation, pagination, checkout return handling, reactive invalidation and error states.
    • Tests and seeds: determinism and CI robustness given expanded SQL tests and seeded transactions.

Possibly related PRs

Suggested labels

DO NOT MERGE

Poem

🐰 I hopped through code with a carrot grin,

Ledgers sprouted where the credits begin.
Stripe made a path and checkout danced along,
Grants and alerts chimed out a tidy song.
Balance topped up — a little rabbit's song.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes a summary of the feature and a test plan, but multiple required checklist items remain unchecked (linting, documentation, E2E tests, manual testing confirmation), and the PR has unresolved reviewer feedback requesting fixes and clarifications. Complete the checklist items by running linting, confirming documentation updates, adding E2E test coverage, and providing manual test results; address all reviewer feedback before merging.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: adding a top-up workflow with Stripe for credits, which aligns with the substantial feature additions across multiple files.

📜 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 690966c and b824821.

📒 Files selected for processing (18)
  • messages/de.json (2 hunks)
  • messages/en.json (2 hunks)
  • messages/es.json (2 hunks)
  • messages/fr.json (4 hunks)
  • messages/hi.json (2 hunks)
  • messages/id.json (2 hunks)
  • messages/it.json (2 hunks)
  • messages/ja.json (2 hunks)
  • messages/ko.json (2 hunks)
  • messages/pl.json (2 hunks)
  • messages/pt-br.json (2 hunks)
  • messages/ru.json (3 hunks)
  • messages/tr.json (2 hunks)
  • messages/vi.json (2 hunks)
  • messages/zh-cn.json (2 hunks)
  • src/auto-imports.d.ts (1 hunks)
  • src/layouts/settings.vue (1 hunks)
  • src/typed-router.d.ts (2 hunks)

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.

@Dalanir Dalanir added enhancement New feature or request DO NOT MERGE labels Oct 29, 2025
@Dalanir
Copy link
Copy Markdown
Contributor Author

Dalanir commented Oct 29, 2025

Don't merge it until #1231 is merged

Base automatically changed from credit-system-v2 to main October 30, 2025 11:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

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

⚠️ Outside diff range comments (1)
messages/hi.json (1)

2-2: $schema is not a valid schema URL

Value includes a newline and a Hindi note, likely breaking schema tooling. Use the canonical URL string only.

-"$schema": "https://inlang.com/schema/inlang-message-format\n\nकृपया ध्यान दें, URL को हम अनुवादित नहीं कर सकते हैं.",
+"$schema": "https://inlang.com/schema/inlang-message-format",
🧹 Nitpick comments (23)
src/components/dashboard/Usage.vue (1)

643-689: Clarify guard and improve progress bar accessibility

  • If intended to show zero-balance state, v-if="creditAvailable" hides the panel; consider using hasCreditSummary or explicit > 0 check per product decision.
  • Add aria roles/labels to the usage bar for screen readers.
-  <div v-if="creditsV2Enabled && !isLoading && creditAvailable" class="mb-6">
+  <div v-if="creditsV2Enabled && !isLoading && creditAvailable > 0" class="mb-6">
...
-          <div class="h-2 w-full rounded-full bg-gray-200 dark:bg-gray-700 overflow-hidden">
-            <div
-              class="h-full rounded-full bg-emerald-500 transition-all"
-              :style="{ width: `${creditUsagePercent}%` }"
-            />
-          </div>
+          <div class="h-2 w-full rounded-full bg-gray-200 dark:bg-gray-700 overflow-hidden" role="progressbar"
+               :aria-valuenow="creditUsagePercent" aria-valuemin="0" :aria-valuemax="100"
+               :aria-label="t('credits-used-in-period')">
+            <div class="h-full rounded-full bg-emerald-500 transition-all"
+                 :style="{ width: `${creditUsagePercent}%` }" />
+          </div>
messages/it.json (1)

275-286: English placeholders in Italian locale for credits

These keys remain English; consider at least short Italian copies before release or explicitly accept fallback.

Also applies to: 292-301, 305-306

messages/zh-cn.json (1)

275-285: English placeholders in Simplified Chinese locale for credits

Translate before shipping or confirm fallback-to-English is acceptable for this release.

Also applies to: 292-298, 299-301, 305-306

messages/fr.json (1)

275-285: English placeholders in French locale for credits

Please localize or confirm temporary English is acceptable.

Also applies to: 292-301, 305-306

messages/pt-br.json (1)

275-285: English placeholders in pt-BR locale for credits

Localize or accept English fallback for this iteration.

Also applies to: 292-301, 305-306

messages/hi.json (1)

275-285: English placeholders in Hindi locale for credits

Translate or confirm English fallback for now.

Also applies to: 292-301, 305-306

src/services/stripe.ts (1)

125-145: Surface user feedback on invalid/missing parameters

Return null silently hides UX issues; show a toast so callers don’t need to duplicate checks.

-export async function completeCreditTopUp(orgId: string, sessionId: string) {
-  if (!orgId || !sessionId)
-    return null
+export async function completeCreditTopUp(orgId: string, sessionId: string) {
+  if (!orgId || !sessionId) {
+    toast.error('Missing required checkout parameters')
+    return null
+  }
supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql (4)

62-69: Balance snapshot timing may be inconsistent with ledger write

You read balances (Lines 62-69) and then write the ledger transaction (Lines 70-88). If usage_credit_balances derives from transactions, the returned total/available and the recorded balance_after can diverge. Prefer inserting the transaction first, then re-querying balances for a consistent “after” snapshot to both store and return.

Would you confirm whether usage_credit_balances is a view over grants/transactions or a materialized table updated by triggers? If it’s the former, re-ordering is essential for consistency. I can propose the exact diff once confirmed.

Also applies to: 70-88, 90-94


28-30: Redundant/fragile role check; rely on SQL privileges or use SQLSTATE

With SECURITY DEFINER and GRANT EXECUTE only to service_role, the explicit role gate is redundant and string-comparison on current_setting is brittle. If you keep it, raise with SQLSTATE 42501 for proper privilege semantics.

Example tweak:

-  IF current_user <> 'postgres' AND COALESCE(v_request_role, '') <> 'service_role' THEN
-    RAISE EXCEPTION 'insufficient_privileges';
+  IF current_user <> 'postgres' AND COALESCE(v_request_role, '') <> 'service_role' THEN
+    RAISE EXCEPTION SQLSTATE '42501' USING MESSAGE = 'insufficient_privileges';
   END IF;

Also applies to: 109-109


40-60: Stripe/webhook idempotency hook missing

source_ref is stored but there’s no uniqueness guard to prevent double-granting on webhook retries. Consider a unique index on a stable id within p_source_ref (e.g., (org_id, (source_ref->>'event_id'))) and handle conflict DO NOTHING/RETURN existing.

I can draft a safe migration to add the constraint and make the INSERT idempotent.

Also applies to: 70-88


1-2: Seed fixtures update reminder

Credits/top‑up features usually require seed data for tests and environments. Please update supabase/seed.sql accordingly and keep prior migrations unchanged. Based on learnings

I can prepare minimal seed rows for usage_credit_grants/usage_credit_transactions to back new tests.

messages/pl.json (2)

275-286: Untranslated strings in Polish locale (credit-transaction-*)

All added values are in English. Please localize before release or confirm intentional fallback. Example: “Amount” → “Kwota”, “Balance after” → “Saldo po”.


292-301: Untranslated credits UI copy

New credits keys are English (“Credits”, “Need more credits?”, etc.). Localize or mark for translation to keep UI consistent for pl users.

Also applies to: 305-305

messages/id.json (2)

275-286: Translate credit-transaction- to Indonesian*

Values are English in id locale. Please provide Indonesian translations (“Amount” → “Jumlah”, “Balance after” → “Saldo setelah”, etc.).


292-301: Translate credits UI strings

“Credits”, “Buy credits”, and related descriptions are English; localize for id.json or confirm fallback policy.

Also applies to: 305-305

messages/ko.json (2)

275-286: Korean locale contains English credit-transaction strings

Localize these values (“Amount” → “금액”, “Balance after” → “이후 잔액”, etc.) to avoid mixed-language UI.


292-301: Credits UI keys need Korean translations

“Credits”, “Need more credits?”, “Buy credits”, etc., are English. Please translate or track as TODO before GA.

Also applies to: 305-305

messages/vi.json (2)

275-286: Translate credit-transaction- to Vietnamese*

Currently English. Suggested examples: “Amount” → “Số tiền”, “Balance after” → “Số dư sau”.


292-301: Translate credits UI strings to Vietnamese

Localize “Credits”, “Buy credits”, and descriptions for vi.json, or confirm intentional fallback.

Also applies to: 305-305

messages/tr.json (2)

275-286: Turkish locale: credit-transaction- values are English*

Please translate (“Amount” → “Tutar”, “Balance after” → “Sonraki bakiye”, etc.) to maintain consistency.


292-301: Translate credits UI copy

New credits strings are English; localize for tr.json or mark for translation before release.

Also applies to: 305-305

messages/es.json (2)

275-286: Spanish locale has English credit-transaction strings

Please translate (e.g., “Amount” → “Importe”, “Balance after” → “Saldo después”, “Refund” → “Reembolso”).


292-301: Credits UI strings need Spanish translations

Localize “Credits”, “Need more credits?”, “Buy credits”, etc., to avoid mixed-language UI.

Also applies to: 305-305

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b551c85 and a35e182.

📒 Files selected for processing (29)
  • messages/de.json (1 hunks)
  • messages/en.json (1 hunks)
  • messages/es.json (1 hunks)
  • messages/fr.json (1 hunks)
  • messages/hi.json (1 hunks)
  • messages/id.json (1 hunks)
  • messages/it.json (1 hunks)
  • messages/ja.json (1 hunks)
  • messages/ko.json (1 hunks)
  • messages/pl.json (1 hunks)
  • messages/pt-br.json (1 hunks)
  • messages/ru.json (1 hunks)
  • messages/tr.json (1 hunks)
  • messages/vi.json (1 hunks)
  • messages/zh-cn.json (1 hunks)
  • src/components/dashboard/Usage.vue (2 hunks)
  • src/layouts/settings.vue (3 hunks)
  • src/pages/settings/Account.vue (1 hunks)
  • src/pages/settings/ChangePassword.vue (1 hunks)
  • src/pages/settings/organization/Credits.vue (1 hunks)
  • src/pages/settings/organization/Members.vue (1 hunks)
  • src/pages/settings/organization/index.vue (1 hunks)
  • src/services/stripe.ts (2 hunks)
  • src/types/supabase.types.ts (29 hunks)
  • supabase/functions/_backend/private/credits.ts (3 hunks)
  • supabase/functions/_backend/utils/hono_middleware_stripe.ts (0 hunks)
  • supabase/functions/_backend/utils/stripe.ts (1 hunks)
  • supabase/functions/_backend/utils/supabase.types.ts (29 hunks)
  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql (1 hunks)
💤 Files with no reviewable changes (1)
  • supabase/functions/_backend/utils/hono_middleware_stripe.ts
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.{vue,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vue.js with Tailwind CSS, favoring utility classes and composition-friendly patterns over bespoke CSS

Files:

  • src/components/dashboard/Usage.vue
  • src/layouts/settings.vue
  • src/pages/settings/organization/index.vue
  • src/pages/settings/organization/Credits.vue
  • src/pages/settings/organization/Members.vue
  • src/pages/settings/ChangePassword.vue
  • src/pages/settings/Account.vue
src/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/components/dashboard/Usage.vue
  • src/layouts/settings.vue
  • src/pages/settings/organization/index.vue
  • src/pages/settings/organization/Credits.vue
  • src/pages/settings/organization/Members.vue
  • src/pages/settings/ChangePassword.vue
  • src/pages/settings/Account.vue
src/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/components/dashboard/Usage.vue
  • src/services/stripe.ts
  • src/layouts/settings.vue
  • src/pages/settings/organization/index.vue
  • src/pages/settings/organization/Credits.vue
  • src/pages/settings/organization/Members.vue
  • src/pages/settings/ChangePassword.vue
  • src/pages/settings/Account.vue
  • src/types/supabase.types.ts
{src/**/*.vue,src/styles/style.css}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo palette (deep slate bases, Extract azure highlight, soft radii) from src/styles/style.css when introducing new UI

Files:

  • src/components/dashboard/Usage.vue
  • src/layouts/settings.vue
  • src/pages/settings/organization/index.vue
  • src/pages/settings/organization/Credits.vue
  • src/pages/settings/organization/Members.vue
  • src/pages/settings/ChangePassword.vue
  • src/pages/settings/Account.vue
supabase/migrations/**

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/**: Use the Supabase CLI for every migration and operational task whenever possible; avoid manual changes through the dashboard or direct SQL
When a feature requires schema changes, create a single migration file with the Supabase CLI and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, but treat that seeding as part of the current feature and do not modify previously committed migrations

Files:

  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
🧠 Learnings (2)
📚 Learning: 2025-10-22T17:04:10.729Z
Learnt from: CR
PR: Cap-go/capgo#0
File: AGENTS.md:0-0
Timestamp: 2025-10-22T17:04:10.729Z
Learning: Applies to src/**/*.{vue,css} : Use Vue.js with Tailwind CSS, favoring utility classes and composition-friendly patterns over bespoke CSS

Applied to files:

  • src/pages/settings/organization/Members.vue
📚 Learning: 2025-10-22T17:04:10.729Z
Learnt from: CR
PR: Cap-go/capgo#0
File: AGENTS.md:0-0
Timestamp: 2025-10-22T17:04:10.729Z
Learning: Applies to supabase/seed.sql : Update supabase/seed.sql to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
🧬 Code graph analysis (4)
supabase/functions/_backend/private/credits.ts (5)
supabase/functions/_backend/utils/hono.ts (3)
  • middlewareAuth (107-115)
  • parseBody (227-238)
  • simpleError (223-225)
supabase/functions/_backend/utils/supabase.ts (2)
  • supabaseAdmin (74-83)
  • hasOrgRight (242-259)
supabase/functions/_backend/utils/utils.ts (1)
  • getEnv (116-120)
supabase/functions/_backend/utils/loggin.ts (1)
  • cloudlog (3-15)
supabase/functions/_backend/utils/stripe.ts (2)
  • createOneTimeCheckout (310-351)
  • getStripe (8-13)
supabase/functions/_backend/utils/stripe.ts (2)
supabase/functions/_backend/utils/utils.ts (1)
  • existInEnv (112-114)
supabase/functions/_backend/utils/loggin.ts (1)
  • cloudlog (3-15)
src/types/supabase.types.ts (1)
supabase/functions/_backend/utils/supabase.types.ts (3)
  • Json (1-7)
  • Enums (2551-2566)
  • Constants (2585-2680)
supabase/functions/_backend/utils/supabase.types.ts (1)
src/types/supabase.types.ts (7)
  • Json (1-7)
  • Database (9-2466)
  • TablesInsert (2501-2524)
  • TablesUpdate (2526-2549)
  • Enums (2551-2566)
  • CompositeTypes (2568-2583)
  • Constants (2585-2680)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (1)
src/pages/settings/Account.vue (1)

11-14: Icon source switch to Heroicons looks good

Imports align with usage (component vs raw). Please confirm vite-icon resolver config covers these heroicons paths.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (8)
messages/hi.json (2)

2-2: $schema must be a single URL (tooling breaks with embedded note/newlines).

Replace the mixed URL+note with the canonical schema URL.

-  "$schema": "https://inlang.com/schema/inlang-message-format\n\nकृपया ध्यान दें, URL को हम अनुवादित नहीं कर सकते हैं.",
+  "$schema": "https://inlang.com/schema/inlang-message-format",

887-887: Mistranslation: “used-in-period” reads as “menstruation period.”

Update to a neutral period phrasing.

-  "used-in-period": "मासिक धर्म के समय उपयोग किया जाता है",
+  "used-in-period": "अवधि में उपयोग",
messages/ru.json (1)

2-2: $schema inválido: contém quebras de linha e texto adicional.

Defina apenas a URL do esquema para compatibilidade com ferramentas.

-  "$schema": "https://inlang.com/schema/inlang-message-format\n\nTranslation: https://inlang.com/schema/format-soobshcheniya-inlang",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
messages/ja.json (1)

2-2: Do not localize $schema URL (breaks tooling).

$schema must be the exact URL. Remove added JP text/newlines.

Apply this diff:

-  "$schema": "https://inlang.com/schema/inlang-message-format\n\nを日本語に翻訳します:\n\nhttps://inlang.com/schema/inlang-メッセージ形式",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
messages/es.json (1)

2-2: Restore exact $schema URL.

Do not translate or alter the path; validators rely on it.

Apply this diff:

-  "$schema": "https://inlang.com/schema/formato-de-mensaje-inlang",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
messages/tr.json (1)

2-2: Remove commentary; keep $schema as exact URL.

Extra text breaks schema detection.

Apply this diff:

-  "$schema": "https://inlang.com/schema/inlang-message-format\n\nThis is a URL and it cannot be translated.",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
messages/vi.json (1)

2-2: Fix $schema URL (must not be localized).

Use the canonical URL.

Apply this diff:

-  "$schema": "https://inlang.com/schema/dinh-dang-tin-nhan-inlang",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
messages/ko.json (1)

2-2: Keep $schema exact; remove localized note.

Only the URL should remain.

Apply this diff:

-  "$schema": "https://inlang.com/schema/inlang-message-format\n\n위의 웹사이트 주소는 언어에 관계없이 동일하게 유지됩니다.",
+  "$schema": "https://inlang.com/schema/inlang-message-format",
♻️ Duplicate comments (4)
messages/ru.json (1)

275-285: RU credit strings localized now; previous issue resolved.

The earlier concern about English leftovers appears fixed; translations look consistent.

Also applies to: 292-301, 304-362, 364-367

messages/ja.json (1)

275-367: JP credit strings look translated and consistent.

The new credit keys read naturally; nice work.

src/layouts/settings.vue (1)

20-20: Fix the feature flag to parse as a real boolean.

import.meta.env always returns strings, so 'false' remains truthy and the Credits tab stays visible even when the flag is disabled. Coerce the value before using it.

-const creditsV2Enabled = import.meta.env.VITE_FEATURE_CREDITS_V2
+const creditsV2Enabled = String(import.meta.env.VITE_FEATURE_CREDITS_V2 ?? '').toLowerCase() === 'true'

(vite.dev)

src/pages/settings/organization/Credits.vue (1)

20-20: Parse the feature flag to a boolean before use.

import.meta.env exposes flag values as strings, so 'false' still evaluates truthy and this page never redirects when the flag is off. Normalize the value before using it.

-const creditsV2Enabled = import.meta.env.VITE_FEATURE_CREDITS_V2
+const creditsV2Enabled = String(import.meta.env.VITE_FEATURE_CREDITS_V2 ?? '').toLowerCase() === 'true'

(vite.dev)

🧹 Nitpick comments (1)
src/layouts/settings.vue (1)

93-95: Drop the leftover debug logs.

These console statements add noise in production and don’t provide end-user value. Please remove them now that the feature flag logic is in place.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a35e182 and baee411.

📒 Files selected for processing (23)
  • messages/de.json (1 hunks)
  • messages/en.json (1 hunks)
  • messages/es.json (1 hunks)
  • messages/fr.json (1 hunks)
  • messages/hi.json (1 hunks)
  • messages/id.json (1 hunks)
  • messages/it.json (1 hunks)
  • messages/ja.json (1 hunks)
  • messages/ko.json (1 hunks)
  • messages/pl.json (1 hunks)
  • messages/pt-br.json (1 hunks)
  • messages/ru.json (1 hunks)
  • messages/tr.json (1 hunks)
  • messages/vi.json (1 hunks)
  • messages/zh-cn.json (1 hunks)
  • src/layouts/settings.vue (3 hunks)
  • src/pages/settings/organization/Credits.vue (1 hunks)
  • src/services/stripe.ts (2 hunks)
  • src/types/supabase.types.ts (18 hunks)
  • supabase/functions/_backend/private/credits.ts (3 hunks)
  • supabase/functions/_backend/utils/stripe.ts (1 hunks)
  • supabase/functions/_backend/utils/supabase.types.ts (18 hunks)
  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/services/stripe.ts
  • messages/it.json
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.{vue,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vue.js with Tailwind CSS, favoring utility classes and composition-friendly patterns over bespoke CSS

Files:

  • src/layouts/settings.vue
  • src/pages/settings/organization/Credits.vue
src/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/layouts/settings.vue
  • src/pages/settings/organization/Credits.vue
src/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/layouts/settings.vue
  • src/pages/settings/organization/Credits.vue
  • src/types/supabase.types.ts
{src/**/*.vue,src/styles/style.css}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo palette (deep slate bases, Extract azure highlight, soft radii) from src/styles/style.css when introducing new UI

Files:

  • src/layouts/settings.vue
  • src/pages/settings/organization/Credits.vue
supabase/migrations/**

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/**: Use the Supabase CLI for every migration and operational task whenever possible; avoid manual changes through the dashboard or direct SQL
When a feature requires schema changes, create a single migration file with the Supabase CLI and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, but treat that seeding as part of the current feature and do not modify previously committed migrations

Files:

  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
🧠 Learnings (2)
📚 Learning: 2025-10-30T14:58:37.007Z
Learnt from: Dalanir
Repo: Cap-go/capgo PR: 1238
File: src/layouts/settings.vue:7-13
Timestamp: 2025-10-30T14:58:37.007Z
Learning: In the Cap-go/capgo repository, heroicons are imported using the pattern `~icons/heroicons/icon-name` (e.g., `~icons/heroicons/user`, `~icons/heroicons/bell`) without requiring `/outline/` or `/solid/` path segments. Solid variants use a `-solid` suffix in the icon name itself (e.g., `~icons/heroicons/arrow-path-solid`).

Applied to files:

  • src/layouts/settings.vue
📚 Learning: 2025-10-22T17:04:10.729Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-22T17:04:10.729Z
Learning: Applies to supabase/seed.sql : Update supabase/seed.sql to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • src/types/supabase.types.ts
  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
🧬 Code graph analysis (4)
src/types/supabase.types.ts (1)
supabase/functions/_backend/utils/supabase.types.ts (1)
  • Json (1-7)
supabase/functions/_backend/private/credits.ts (5)
supabase/functions/_backend/utils/hono.ts (4)
  • MiddlewareKeyVariables (26-40)
  • simpleError (223-225)
  • middlewareAuth (107-115)
  • parseBody (227-238)
supabase/functions/_backend/utils/supabase.ts (2)
  • supabaseAdmin (74-83)
  • hasOrgRight (242-259)
supabase/functions/_backend/utils/utils.ts (1)
  • getEnv (116-120)
supabase/functions/_backend/utils/loggin.ts (1)
  • cloudlog (3-15)
supabase/functions/_backend/utils/stripe.ts (2)
  • createOneTimeCheckout (307-353)
  • getStripe (8-13)
supabase/functions/_backend/utils/stripe.ts (2)
supabase/functions/_backend/utils/utils.ts (1)
  • existInEnv (112-114)
supabase/functions/_backend/utils/loggin.ts (1)
  • cloudlog (3-15)
supabase/functions/_backend/utils/supabase.types.ts (1)
src/types/supabase.types.ts (6)
  • Database (9-2474)
  • Json (1-7)
  • TablesInsert (2509-2532)
  • TablesUpdate (2534-2557)
  • Enums (2559-2574)
  • CompositeTypes (2576-2591)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (4)
messages/hi.json (1)

275-285: Credits strings look consistent; placeholders preserved.

The added credit and pricing keys read well in Hindi; {amount} is intact. LGTM.

Also applies to: 292-301, 304-362, 364-367

messages/fr.json (1)

275-285: Crédits/prix: bon libellé et variables conservées.

Traductions fluides; {amount} conservé; unités cohérentes (GiB/To). LGTM.

Also applies to: 292-301, 304-362, 364-367

messages/pt-br.json (1)

275-285: Bloco de créditos e preços OK.

Chaves novas consistentes; placeholder {amount} mantido. LGTM.

Also applies to: 292-301, 304-362, 364-367

messages/en.json (1)

275-285: Credit keys verified across all 15 locales with {amount} placeholder preserved.

All verification checks pass: 86 baseline credit-related keys are consistently present across all locales (de, en, es, fr, hi, id, it, ja, ko, pl, pt-br, ru, tr, vi, zh-cn), and the {amount} placeholder is preserved in credits-top-up-total-estimate across the full locale set.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between baee411 and b4c7b0c.

📒 Files selected for processing (1)
  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
supabase/migrations/**

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/**: Use the Supabase CLI for every migration and operational task whenever possible; avoid manual changes through the dashboard or direct SQL
When a feature requires schema changes, create a single migration file with the Supabase CLI and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, but treat that seeding as part of the current feature and do not modify previously committed migrations

Files:

  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
🧠 Learnings (1)
📚 Learning: 2025-10-22T17:04:10.729Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-22T17:04:10.729Z
Learning: Applies to supabase/seed.sql : Update supabase/seed.sql to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (3)
supabase/migrations/20251024155313_add_top_up_usage_credits_rpc.sql (3)

96-97: Previous critical issue fixed correctly.

The missing final RETURN; statement that was flagged in prior review has been properly addressed. The sequence RETURN NEXT; followed by RETURN; is now correct for a plpgsql set-returning function.


82-82: Previous transaction type issue fixed.

The transaction ledger now correctly uses 'purchase' instead of 'grant' for Stripe-funded top-ups, ensuring proper classification for reporting and UI consistency.


1-114: Migration structure and compatibility.

The migration properly wraps the function creation in an explicit transaction and uses Supabase CLI conventions (single migration file for the feature). The function grants execute permissions to service_role and includes a descriptive COMMENT. The implementation follows SQL and plpgsql best practices for a SECURITY DEFINER function with explicit search_path setting.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

♻️ Duplicate comments (4)
messages/ru.json (1)

297-411: Localizations for credits look good; translate “plan” value

The credits and pricing blocks are now properly localized (no English leftovers, placeholders intact, and no duplicate credits-balance), which is good.

However, the "plan" value is still English:

"plan": "Plan"

For consistency with the rest of the Russian locale, translate it, for example:

-  "plan": "Plan",
+  "plan": "План",

(or another RU term you standardize on, such as "Тариф").

Also applies to: 748-748

messages/pt-br.json (1)

297-411: Credits strings are localized; update “plan” to pt‑BR

The new credits, pricing, and top‑up keys are well localized in pt‑BR, with placeholders preserved and duplicate keys removed.

The "plan" entry, however, is still English:

"plan": "Plan"

To match the rest of the locale, update it to Portuguese:

-  "plan": "Plan",
+  "plan": "Plano",

Also applies to: 748-748

messages/ko.json (1)

748-748: Translate “plan” key to Korean.

Use locale-consistent term.

-  "plan": "Plan",
+  "plan": "플랜",
messages/zh-cn.json (1)

327-327: Unify to Simplified Chinese "积分" (remove Traditional "積分").

The file mixes Traditional and Simplified characters for "credit points." Lines 327, 397–398, 399, 401, and 411 contain Traditional "積分", while the rest of the file uses Simplified "积分". Replace all occurrences with Simplified "积分" for consistency within zh-CN locale:

-  "credits-pricing-description": "積分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
+  "credits-pricing-description": "积分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
-  "credits-pricing-disclaimer": "積分用于覆盖超出套餐包含限制的用量。積分需预付并在 12 个月内有效。",
+  "credits-pricing-disclaimer": "积分用于覆盖超出套餐包含限制的用量。积分需预付并在 12 个月内有效。",
-  "no-credits-available": "还没有積分。购买積分包以扩展套餐用量。",
+  "no-credits-available": "还没有积分。购买积分包以扩展套餐用量。",
-  "credits-top-up-quantity-label": "购买的積分",
+  "credits-top-up-quantity-label": "购买的积分",
-  "credits-top-up-quantity-invalid": "继续之前请输入有效的積分数量。",
+  "credits-top-up-quantity-invalid": "继续之前请输入有效的积分数量。",
-  "buy-credits": "购买積分",
+  "buy-credits": "购买积分",
🧹 Nitpick comments (3)
messages/de.json (1)

323-327: Use consistent German terminology (“Guthaben”) instead of “Credit”.

Align with “credits”: “Guthaben”.

-  "credits-balance": "Credit-Guthaben",
+  "credits-balance": "Guthaben",
-  "credits-next-expiration": "Nächste Credit-Ablauffrist",
+  "credits-next-expiration": "Nächste Guthaben-Ablauffrist",
-  "credits-pricing-title": "Credit-Preise",
+  "credits-pricing-title": "Guthaben-Preise",
messages/fr.json (1)

382-395: Refine build‑tier phrasing to idiomatic French.

Use “X minutes suivantes” and “100 premières minutes” for natural wording.

-  "credits-pricing-build-tier-first-100": "Premières 100 minutes",
+  "credits-pricing-build-tier-first-100": "100 premières minutes",
-  "credits-pricing-build-tier-next-400": "Prochaines 400 minutes",
+  "credits-pricing-build-tier-next-400": "400 minutes suivantes",
-  "credits-pricing-build-tier-next-500": "Prochaines 500 minutes",
+  "credits-pricing-build-tier-next-500": "500 minutes suivantes",
-  "credits-pricing-build-tier-next-4000": "Prochaines 4 000 minutes",
+  "credits-pricing-build-tier-next-4000": "4 000 minutes suivantes",
-  "credits-pricing-build-tier-next-5000": "Prochaines 5 000 minutes",
+  "credits-pricing-build-tier-next-5000": "5 000 minutes suivantes",
-  "credits-pricing-build-tier-over-10000": "Au-delà de 10 000 minutes",
+  "credits-pricing-build-tier-over-10000": "Au‑delà de 10 000 minutes",
messages/ja.json (1)

297-307: Add locale validation checks to prevent regressions.

The suggestion to add a sanity check script is sound. The checks for duplicate keys, {amount} placeholder in credits-top-up-total-estimate, and {current}/{total} placeholders in credits-pagination-label are all valid and currently pass across all 15 locale files. Running these checks as part of CI would catch issues early if keys or placeholders are accidentally modified or removed.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3380385 and 43ffc6e.

📒 Files selected for processing (16)
  • messages/de.json (2 hunks)
  • messages/es.json (2 hunks)
  • messages/fr.json (3 hunks)
  • messages/hi.json (2 hunks)
  • messages/id.json (2 hunks)
  • messages/it.json (2 hunks)
  • messages/ja.json (2 hunks)
  • messages/ko.json (2 hunks)
  • messages/pl.json (2 hunks)
  • messages/pt-br.json (2 hunks)
  • messages/ru.json (2 hunks)
  • messages/tr.json (2 hunks)
  • messages/vi.json (2 hunks)
  • messages/zh-cn.json (2 hunks)
  • src/constants/organizationTabs.ts (2 hunks)
  • src/pages/settings/organization/Plans.vue (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
{supabase/functions/_backend/**/*.ts,src/**/*.{ts,vue}}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend code must use ./utils/ import paths for utility functions; frontend code must use ~/ alias for src/ directory imports

Files:

  • src/constants/organizationTabs.ts
  • src/pages/settings/organization/Plans.vue
{src/**/*.{ts,js,vue},supabase/**/*.{ts,js}}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run bun lint:fix before committing code to auto-fix linting issues; never commit without running this command

Files:

  • src/constants/organizationTabs.ts
  • src/pages/settings/organization/Plans.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • src/constants/organizationTabs.ts
  • src/pages/settings/organization/Plans.vue
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • src/constants/organizationTabs.ts
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}

📄 CodeRabbit inference engine (CLAUDE.md)

Mobile apps should use Capacitor with app ID ee.forgr.capacitor_go for native mobile functionality

Files:

  • src/constants/organizationTabs.ts
  • src/pages/settings/organization/Plans.vue
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use <script setup> syntax exclusively in Vue components; do not use Options API
Use Tailwind utility classes for layout and spacing; use DaisyUI components (d-btn, d-input, d-card) for interactive elements
Use Konsta components ONLY for safe area helpers (top/bottom insets); avoid using Konsta for general UI components

src/**/*.vue: Use Vue 3 with Composition API and <script setup> syntax for frontend components
Style components using TailwindCSS with DaisyUI components

src/**/*.vue: Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent
Konsta components are reserved for the safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/pages/settings/organization/Plans.vue
src/**/*.{vue,css}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Avoid custom CSS; prefer Tailwind utility composition and DaisyUI theming from src/styles/style.css

src/**/*.{vue,css}: The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS
Capgo's look centers on deep slate bases with the 'Extract' azure highlight (--color-azure-500: #119eff) and soft radii; mirror the palette from src/styles/style.css when introducing new UI

Files:

  • src/pages/settings/organization/Plans.vue
src/pages/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/pages/**/*.vue: Frontend pages auto-route via unplugin-vue-router based on file structure in src/pages/, use useRoute() for params and useRouter() for navigation
Use useRoute() from vue-router to access route parameters in page components

Use file-based routing with unplugin-vue-router for frontend pages

Files:

  • src/pages/settings/organization/Plans.vue
🧠 Learnings (1)
📚 Learning: 2025-10-30T14:58:37.007Z
Learnt from: Dalanir
Repo: Cap-go/capgo PR: 1238
File: src/layouts/settings.vue:7-13
Timestamp: 2025-10-30T14:58:37.007Z
Learning: In the Cap-go/capgo repository, heroicons are imported using the pattern `~icons/heroicons/icon-name` (e.g., `~icons/heroicons/user`, `~icons/heroicons/bell`) without requiring `/outline/` or `/solid/` path segments. Solid variants use a `-solid` suffix in the icon name itself (e.g., `~icons/heroicons/arrow-path-solid`).

Applied to files:

  • src/constants/organizationTabs.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). (1)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (9)
src/constants/organizationTabs.ts (1)

4-13: Credits tab wiring and icon import look correct

IconCredits import path and ordering are consistent with existing heroicons usage, and the new credits tab key matches the /settings/organization/credits route used by the new page. No issues from a routing or style perspective. Based on learnings, the icon import pattern is correct.

messages/pl.json (1)

297-411: Polish credits translations and placeholders look consistent

The new credit transaction, pricing, daily breakdown, and top‑up strings are properly localized, placeholders ({amount}, {metric}, {count}, {current}, {total}) are preserved, and credits-balance is no longer duplicated. No further changes needed here.

messages/tr.json (1)

297-411: Turkish credits translations and pricing block are consistent

The added credit transaction, pricing, top‑up, and daily usage strings are correctly localized, the build‑time pricing block is no longer in English, and placeholders are preserved. No remaining issues in this section.

messages/es.json (1)

314-395: LGTM: credits, pricing, and top-up block reads well in Spanish.

Copy, units, and placeholders look consistent.

Also applies to: 398-411

messages/ja.json (1)

297-307: Credits block localization looks solid.

Strings are natural, placeholders are preserved ({amount}, {current}, {total}), and prior duplicate-key issues appear resolved. Nice work.

Also applies to: 314-346, 346-399, 399-411

messages/hi.json (1)

314-346: Credits localization: good coverage.

New credits and pricing strings are consistent and placeholders intact.

Also applies to: 346-399, 399-411

messages/id.json (1)

382-395: Build-time pricing localized correctly.

Terminology and number formatting are consistent with the rest of the file.

messages/vi.json (1)

382-396: Resolved: build pricing, “plan”, and top-up copy.

  • Build-time pricing is fully localized.
  • “plan” correctly translated.
  • “Nạp tín dụng thành công.” fixes mixed-language phrase.

Also applies to: 402-402, 748-748

messages/fr.json (1)

297-307: Credits localization looks consistent and complete.

Good coverage of transactions, pricing, and top‑up; placeholders preserved.

Also applies to: 314-346, 346-399, 399-411

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (3)
messages/ko.json (2)

613-616: Duplicate JSON key: "general" — remove the later occurrence.

"general" appears twice; the later one overrides the earlier and breaks linting.

Apply this diff to keep the first value and remove the duplicate here:

-  "general": "일반적인",

672-672: Localize “last-x-hours”.

Value is still English. Suggested:

-  "last-x-hours": "Last {hours} hours",
+  "last-x-hours": "지난 {hours}시간",
messages/ja.json (1)

670-670: Localize “last-x-hours”.

Translate to natural Japanese.

-  "last-x-hours": "Last {hours} hours",
+  "last-x-hours": "過去{hours}時間",
♻️ Duplicate comments (8)
messages/pt-br.json (1)

816-816: Translate “plan”.

Use pt-BR term for consistency.

-  "plan": "Plan",
+  "plan": "Plano",
messages/ja.json (1)

816-816: Translate “plan”.

Align with surrounding plan keys.

-  "plan": "Plan",
+  "plan": "プラン",
messages/ko.json (1)

818-818: Translate “plan”.

Use the locale term to match nearby keys.

-  "plan": "Plan",
+  "plan": "플랜",
messages/zh-cn.json (2)

391-391: Fix Simplified Chinese consistency (“积分”, not “積分”)

Several credit strings use Traditional “積分” within zh-CN. Replace with Simplified “积分”. This aligns with earlier feedback.

Apply this diff:

-  "credits-pricing-description": "積分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
+  "credits-pricing-description": "积分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
@@
-  "credits-pricing-disclaimer": "積分用于覆盖超出套餐包含限制的用量。積分需预付并在 12 个月内有效。",
-  "no-credits-available": "还没有積分。购买積分包以扩展套餐用量。",
-  "credits-top-up-quantity-label": "购买的積分",
+  "credits-pricing-disclaimer": "积分用于覆盖超出套餐包含限制的用量。积分需预付并在 12 个月内有效。",
+  "no-credits-available": "还没有积分。购买积分包以扩展套餐用量。",
+  "credits-top-up-quantity-label": "购买的积分",
@@
-  "credits-top-up-quantity-invalid": "继续之前请输入有效的積分数量。",
+  "credits-top-up-quantity-invalid": "继续之前请输入有效的积分数量。",
@@
-  "buy-credits": "购买積分",
+  "buy-credits": "购买积分",

Also applies to: 461-466, 475-475


816-816: Translate “plan” to Simplified Chinese

Use “计划” for consistency with other entries.

-  "plan": "Plan",
+  "plan": "计划",
messages/it.json (1)

816-816: Translate “plan” to Italian

Use “Piano” to match locale.

-  "plan": "Plan",
+  "plan": "Piano",
messages/id.json (1)

815-815: Localize “plan”.

Use Indonesian for consistency.

-  "plan": "Plan",
+  "plan": "Rencana",
messages/hi.json (1)

815-815: Localize “plan”.

Use Hindi to match surrounding keys.

-  "plan": "Plan",
+  "plan": "योजना",
🧹 Nitpick comments (2)
messages/vi.json (2)

383-385: Use consistent term “tín dụng”.

Align with other credit strings.

-  "credits-used-in-period": "Số điểm đã sử dụng trong kỳ",
+  "credits-used-in-period": "Tín dụng đã dùng trong kỳ",

445-446: Prefer “xây dựng” over “build”.

Keep Vietnamese wording consistent.

-  "credits-pricing-build-title": "Thời gian build (phút)",
-  "credits-pricing-build-subtitle": "Tính cho mỗi phút build vượt quá những gì gói của bạn bao gồm.",
+  "credits-pricing-build-title": "Thời gian xây dựng (phút)",
+  "credits-pricing-build-subtitle": "Tính cho mỗi phút xây dựng vượt quá những gì gói của bạn bao gồm.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43ffc6e and 3d9f574.

📒 Files selected for processing (16)
  • messages/de.json (2 hunks)
  • messages/en.json (2 hunks)
  • messages/es.json (2 hunks)
  • messages/fr.json (3 hunks)
  • messages/hi.json (2 hunks)
  • messages/id.json (2 hunks)
  • messages/it.json (2 hunks)
  • messages/ja.json (2 hunks)
  • messages/ko.json (2 hunks)
  • messages/pl.json (2 hunks)
  • messages/pt-br.json (2 hunks)
  • messages/ru.json (2 hunks)
  • messages/tr.json (2 hunks)
  • messages/vi.json (2 hunks)
  • messages/zh-cn.json (2 hunks)
  • src/services/supabase.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/services/supabase.ts
  • messages/ru.json
🧰 Additional context used
🪛 Biome (2.1.2)
messages/ko.json

[error] 435-436: The key create-a-free-account was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (8)
messages/tr.json (1)

360-371: LGTM: Turkish credits and pricing translations look good.

Placeholders retained; pricing tiers coherent.

Also applies to: 378-468

messages/ko.json (1)

360-372: Sanity check for duplicates/placeholders in this file — verified.

All checks passed: JSON is valid with 1054 keys and no duplicates. Required placeholders are intact:

  • credits-top-up-total-estimate has {amount}
  • credits-daily-deduction-title has {metric}
  • credits-pagination-label has {current} and {total}
messages/es.json (1)

447-460: Build pricing block translation looks solid

Phrasing, numerals, and “por minuto” formatting are correct.

messages/en.json (1)

467-467: Placeholder and duplicate key verification passed

All locale files (de, en, es, fr, hi, id, it, ja, ko, pl, pt-br, ru, tr, vi, zh-cn) correctly include the {amount} placeholder in the credits-top-up-total-estimate key, and none contain duplicate JSON keys.

messages/de.json (1)

360-475: LGTM for new credits/pricing translations.

Keys, placeholders, and pricing phrasing look consistent.

Also applies to: 378-389, 390-461, 462-475, 816-837

messages/hi.json (1)

359-474: All i18n sanity checks pass for new credits keys.

Verified:

  • No duplicate keys in messages/hi.json or other locale files
  • All 4 new placeholders ({amount}, {metric}, {count}, {current}, {total}) present and correctly formatted across locale samples (en, es, fr, de tested)

The credits keys implementation is ready.

messages/fr.json (2)

445-458: Previous critical issue resolved: Build-time pricing now fully translated to French.

All build-time pricing keys (lines 445–458) are now properly translated. The section maintains consistency with other pricing tiers and uses appropriate French terminology throughout.


359-474: New credits system keys fully translated and properly integrated.

All 116+ new translation keys for the credits system—covering transactions, balance tracking, pricing tiers (MAU, bandwidth, storage, build), top-up workflows, and daily activity breakdowns—are translated to French with consistent terminology and formatting. Previous duplicate-key issues have been resolved. No syntax or structural issues detected.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
messages/ko.json (2)

292-299: Fix duplicate key “create-a-free-account” (JSON override bug)

The key appears twice; the latter overrides the former and trips Biome. Remove one occurrence to keep a single definition.

Apply one of these diffs (keep whichever translation you prefer):

Option A — keep earlier, remove later:

@@
-  "create-a-free-accoun": "무료 계정을 생성하십시오",
-  "create-a-free-account": "무료 계정을 생성하십시오",
+  "create-a-free-accoun": "무료 계정을 생성하십시오",

Option B — keep later, remove earlier:

@@
-  "create-a-free-account": "무료 계정을 생성하십시오",
+  /* removed duplicate; later definition kept */

Also applies to: 372-376


14-16: Remove duplicate key “general” (JSON override bug)

“general” is defined twice with different values, causing a silent override. Keep only one.

Suggested fix — remove the later one:

-  "general": "일반적인",

Also applies to: 612-616

♻️ Duplicate comments (1)
messages/zh-cn.json (1)

391-391: Unify “积分” (Simplified) — replace remaining Traditional “積分”.

These changed lines still use “積分”; standardize to Simplified “积分” for zh-CN.

Apply:

-  "credits-pricing-description": "積分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
+  "credits-pricing-description": "积分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
-  "credits-pricing-disclaimer": "積分用于覆盖超出套餐包含限制的用量。積分需预付并在 12 个月内有效。",
+  "credits-pricing-disclaimer": "积分用于覆盖超出套餐包含限制的用量。积分需预付并在 12 个月内有效。",
-  "no-credits-available": "还没有積分。购买積分包以扩展套餐用量。",
+  "no-credits-available": "还没有积分。购买积分包以扩展套餐用量。",
-  "credits-top-up-quantity-label": "购买的積分",
+  "credits-top-up-quantity-label": "购买的积分",
-  "credits-top-up-quantity-invalid": "继续之前请输入有效的積分数量。",
+  "credits-top-up-quantity-invalid": "继续之前请输入有效的积分数量。",
-  "buy-credits": "购买積分",
+  "buy-credits": "购买积分",

To catch any other leftovers:

#!/bin/bash
rg -n "積分" messages/zh-cn.json || echo "✓ No remaining Traditional characters for 积分"

Also applies to: 461-466, 475-475

🧹 Nitpick comments (3)
messages/ru.json (1)

392-409: Unify “MAU” rendering across the locale

At the top “MAU” is localized as “МАУ” (Cyrillic), while pricing uses Latin “MAU” (e.g., “$0.003 за MAU”). Pick one and use it consistently across the file to avoid mixed terms (prefer keeping Latin “MAU” or consistently use “МАУ”).

Also applies to: 395-409

messages/ko.json (1)

816-819: Terminology consistency for “plan”

Consider using “플랜” (commonly used in this locale) instead of “계획” to align with other plan-related strings.

-  "plan": "계획",
+  "plan": "플랜",
messages/id.json (1)

390-391: Minor copy tweak: “mencakup” reads more natural than “menutup”.

Optional, improves fluency without changing meaning.

-  "credits-pricing-description": "Kredit menutup penggunaan yang melampaui batas paket Anda. Gunakan tingkatan ini untuk memperkirakan jumlah yang perlu dibeli.",
+  "credits-pricing-description": "Kredit mencakup penggunaan yang melampaui batas paket Anda. Gunakan tingkatan ini untuk memperkirakan jumlah yang perlu dibeli.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d9f574 and 382dfa5.

📒 Files selected for processing (9)
  • messages/hi.json (2 hunks)
  • messages/id.json (2 hunks)
  • messages/it.json (2 hunks)
  • messages/ja.json (2 hunks)
  • messages/ko.json (2 hunks)
  • messages/pt-br.json (2 hunks)
  • messages/ru.json (2 hunks)
  • messages/zh-cn.json (2 hunks)
  • supabase/tests/26_test_rls_policies.sql (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • supabase/tests/26_test_rls_policies.sql
🧰 Additional context used
🪛 Biome (2.1.2)
messages/ko.json

[error] 435-436: The key create-a-free-account was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (3)
messages/ja.json (1)

360-370: Credits/pricing block localization looks good

Translations are natural, placeholders ({metric}, {count}, {current}, {total}) preserved, and pricing tiers are consistent.

Also applies to: 378-476

messages/pt-br.json (1)

360-370: pt-BR credits/pricing block looks solid

Natural translations, placeholders retained, and tier phrasing consistent.

Also applies to: 378-476

messages/hi.json (1)

359-369: LGTM: translations and placeholders read well.

Strings are consistent; variables like {amount}/{metric}/{count} are intact. No action needed.

Also applies to: 377-390, 391-475, 815-815

Comment on lines +360 to +370
"credit-transaction-amount": "Importo",
"credit-transaction-balance": "Nuovo saldo",
"credit-transaction-description": "Descrizione",
"credit-transaction-deduction": "Detrazione per utilizzo",
"credit-transaction-expiry": "Scadenza",
"credit-transaction-grant": "Assegnazione",
"credit-transaction-manual_grant": "Assegnazione manuale",
"credit-transaction-occurred-at": "Data",
"credit-transaction-purchase": "Acquisto",
"credit-transaction-refund": "Rimborso",
"credit-transaction-type": "Tipo",
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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the messages directory and check if it.json exists
find . -name "it.json" -path "*/messages/*" -type f 2>/dev/null | head -5

Repository: Cap-go/capgo

Length of output: 74


🏁 Script executed:

#!/bin/bash
# Get the structure of messages directory
ls -la messages/ 2>/dev/null || find . -type d -name "messages" | head -3

Repository: Cap-go/capgo

Length of output: 1143


🏁 Script executed:

#!/bin/bash
# Read the specific lines from messages/it.json (lines 360-370)
if [ -f "messages/it.json" ]; then
  wc -l messages/it.json
  echo "=== Lines 360-370 ==="
  sed -n '360,370p' messages/it.json
fi

Repository: Cap-go/capgo

Length of output: 619


🏁 Script executed:

#!/bin/bash
# Check lines 378-390
echo "=== Lines 378-390 ==="
sed -n '378,390p' messages/it.json
echo ""
echo "=== Lines 391-475 (sampling first 30 and last 10) ==="
sed -n '391,420p' messages/it.json
echo "... (middle section) ..."
sed -n '466,475p' messages/it.json

Repository: Cap-go/capgo

Length of output: 3586


🏁 Script executed:

#!/bin/bash
# Check line 816
echo "=== Line 816 ==="
sed -n '816p' messages/it.json

Repository: Cap-go/capgo

Length of output: 91


🏁 Script executed:

#!/bin/bash
# Search for placeholders like {amount}, {metric}, {count}, {current}/{total}
echo "=== Placeholders found in messages/it.json ==="
rg -n '\{(amount|metric|count|current|total)\}' messages/it.json | head -20

Repository: Cap-go/capgo

Length of output: 438


🏁 Script executed:

#!/bin/bash
# Check for duplicate keys in it.json
python3 << 'PYSCRIPT'
import json
import sys

try:
    with open('messages/it.json', 'r', encoding='utf-8') as f:
        content = json.load(f)
    print(f"✓ Valid JSON with {len(content)} keys")
    
    # Check for duplicates by reading line by line with lower-level parsing
    with open('messages/it.json', 'r', encoding='utf-8') as f:
        lines = f.readlines()
    
    keys_seen = {}
    for i, line in enumerate(lines, 1):
        # Simple regex to extract keys
        if '":' in line:
            key_part = line.split('":')[0].strip().strip('"')
            if key_part and not key_part.startswith('{'):  # Skip non-key lines
                if key_part in keys_seen:
                    print(f"DUPLICATE: '{key_part}' at line {i} (first seen at line {keys_seen[key_part]})")
                else:
                    keys_seen[key_part] = i
    
    if len(keys_seen) == len(content):
        print(f"✓ No duplicate keys detected ({len(keys_seen)} unique keys)")
    
except json.JSONDecodeError as e:
    print(f"✗ Invalid JSON: {e}")
    sys.exit(1)
PYSCRIPT

Repository: Cap-go/capgo

Length of output: 195


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of "filter-actions"
echo "=== Searching for 'filter-actions' ==="
rg -n '"filter-actions"' messages/it.json

Repository: Cap-go/capgo

Length of output: 161


🏁 Script executed:

#!/bin/bash
# Test the verification script provided in the review comment
cd /tmp && cp /repo/messages/*.json . && cat > verify_translations.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail

# 1) Fail fast on duplicate keys across all locales
for f in *.json; do
  echo "Checking $f for duplicates..."
  python3 - <<'PY' "$f"
import json,sys
def hook(items):
  seen=set()
  for k,_ in items:
    if k in seen: raise SystemExit(f"Duplicate key in {sys.argv[1]}: {k}")
    seen.add(k)
  return dict(items)
json.load(open(sys.argv[1],encoding='utf-8'), object_pairs_hook=hook)
PY
done
echo "✓ No duplicate keys"

# 2) Ensure {amount} placeholder exists wherever total-estimate appears
fail=0
for f in *.json; do
  if rg -n '"credits-top-up-total-estimate"' "$f" >/dev/null 2>&1; then
    if ! rg -nP '\{amount\}' "$f" >/dev/null 2>&1; then
      echo "Missing {amount} in $f"
      fail=1
    fi
  fi
done
test $fail -eq 0 && echo "✓ All total-estimate keys include {amount}"
SCRIPT
chmod +x verify_translations.sh
./verify_translations.sh 2>&1 | head -50

Repository: Cap-go/capgo

Length of output: 284


🏁 Script executed:

#!/bin/bash
# Run the verification script directly from repo root
set -euo pipefail

# Test the duplicate detection part on it.json
python3 << 'PYSCRIPT'
import json
import sys

def hook(items):
    seen = set()
    for k, _ in items:
        if k in seen:
            print(f"ERROR: Duplicate key found: {k}")
            sys.exit(1)
        seen.add(k)
    return dict(items)

try:
    with open('messages/it.json', encoding='utf-8') as f:
        json.load(f, object_pairs_hook=hook)
    print("✓ No duplicate keys detected")
except SystemExit as e:
    print(f"✗ Duplicate key detection failed")
    sys.exit(1)
PYSCRIPT

Repository: Cap-go/capgo

Length of output: 131


🏁 Script executed:

#!/bin/bash
# Verify the specific placeholder check for total-estimate
echo "=== Checking total-estimate and {amount} placeholder ==="
if grep -n '"credits-top-up-total-estimate"' messages/it.json | grep -q '{amount}'; then
    echo "✓ credits-top-up-total-estimate contains {amount}"
else
    echo "✗ credits-top-up-total-estimate missing {amount}"
fi

# Also check all instances to be thorough
grep -n '"credits-top-up-total-estimate"' messages/it.json

Repository: Cap-go/capgo

Length of output: 245


🏁 Script executed:

#!/bin/bash
# Check if the duplicate key issue exists in other locale files too
echo "=== Checking for 'filter-actions' duplicates in all locale files ==="
for f in messages/*.json; do
    count=$(grep -c '"filter-actions"' "$f" || true)
    if [ "$count" -gt 1 ]; then
        echo "$f: $count occurrences"
        grep -n '"filter-actions"' "$f"
    fi
done

Repository: Cap-go/capgo

Length of output: 909


Critical issue: Duplicate keys found across all locale files.

The review's claim of "No duplicate keys observed" is incorrect. The "filter-actions" key appears twice in messages/it.json (lines 11 and 601), and this pattern repeats across all 8 locale files (de, it, ja, ko, pl, ru, tr, zh-cn). The second occurrence overwrites the first in valid JSON parsing.

The specific lines reviewed (360-370, 378-390, 391-475, 816) are correct and contain consistent, well-formed placeholders ({amount}, {metric}, {count}, {current}/{total}). However, the approval should be conditional on resolving the duplicate key issue first.

The suggested verification script using object_pairs_hook is accurate and correctly detects this problem—it should be run and acted upon before merging.

🤖 Prompt for AI Agents
In messages/it.json around lines 360 to 370 (and other locales where duplicates
exist), there are duplicate JSON keys (e.g., "filter-actions" appears twice)
which cause the second entry to overwrite the first; locate all duplicated keys
across the 8 locale files (de, it, ja, ko, pl, ru, tr, zh-cn), remove or
consolidate the duplicate entries so each key is unique, merge any differing
values into the correct single key (or rename if both are required), update the
translations accordingly, and re-run the provided object_pairs_hook detection
script to verify no duplicates remain before merging.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
messages/zh-cn.json (1)

390-390: Unify to Simplified Chinese "积分" (replace remaining "積分").

The file uses mixed character encodings; these lines contain Traditional Chinese "積分" which must be replaced with Simplified Chinese "积分" for consistency with zh-cn locale:

-  "credits-pricing-description": "積分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
+  "credits-pricing-description": "积分可覆盖超出套餐限制的用量。使用以下分级来估算需要购买的数量。",
-  "credits-pricing-disclaimer": "積分用于覆盖超出套餐包含限制的用量。積分需预付并在 12 个月内有效。",
+  "credits-pricing-disclaimer": "积分用于覆盖超出套餐包含限制的用量。积分需预付并在 12 个月内有效。",
-  "no-credits-available": "还没有積分。购买積分包以扩展套餐用量。",
+  "no-credits-available": "还没有积分。购买积分包以扩展套餐用量。",
-  "credits-top-up-quantity-label": "购买的積分",
+  "credits-top-up-quantity-label": "购买的积分",
-  "credits-top-up-quantity-invalid": "继续之前请输入有效的積分数量。",
+  "credits-top-up-quantity-invalid": "继续之前请输入有效的积分数量。",
-  "buy-credits": "购买積分",
+  "buy-credits": "购买积分",
messages/ko.json (1)

814-815: Use locale‑consistent term for “plan”.

In this locale, “플랜” is commonly used across UI; switch from “계획” for consistency. This was raised earlier.

-  "plan": "계획",
+  "plan": "플랜",
🧹 Nitpick comments (9)
messages/ru.json (2)

470-470: Use ICU plurals for Russian counts.

Avoid "{count} ..." to handle 1/2/5 correctly.

-  "credits-daily-deduction-count": "{count} списаний",
+  "credits-daily-deduction-count": "{count, plural, one {# списание} few {# списания} many {# списаний} other {# списания}}",

-  "credits-daily-transaction-count": "{count} транзакций",
+  "credits-daily-transaction-count": "{count, plural, one {# транзакция} few {# транзакции} many {# транзакций} other {# транзакции}}",

Also applies to: 473-473


453-453: Prevent line breaks in large numerals.

Use a non‑breaking thin space for thousands to avoid UI wraps.

-  "credits-pricing-build-tier-next-4000": "Следующие 4 000 минут",
+  "credits-pricing-build-tier-next-4000": "Следующие 4 000 минут",
-  "credits-pricing-build-tier-next-5000": "Следующие 5 000 минут",
+  "credits-pricing-build-tier-next-5000": "Следующие 5 000 минут",
-  "credits-pricing-build-tier-over-10000": "Свыше 10 000 минут",
+  "credits-pricing-build-tier-over-10000": "Свыше 10 000 минут",

Also applies to: 455-455, 457-457

messages/tr.json (1)

445-446: Prefer “Derleme” over “Build” for consistency.

Align with Turkish terminology across UI.

-  "credits-pricing-build-title": "Build süresi (dakika)",
-  "credits-pricing-build-subtitle": "Planınıza dahil olanın ötesinde yapılan build süresi için dakika başına.",
+  "credits-pricing-build-title": "Derleme süresi (dakika)",
+  "credits-pricing-build-subtitle": "Planınıza dahil olanın ötesindeki derleme için dakika başına.",
messages/ja.json (1)

469-469: Use Japanese-style parentheses instead of em dash.

Improves naturalness: “控除({metric})”.

-  "credits-daily-deduction-title": "控除 — {metric}",
+  "credits-daily-deduction-title": "控除({metric})",
messages/pt-br.json (1)

469-469: Add ICU plurals for Portuguese counts.

Handle singular vs plural.

-  "credits-daily-deduction-count": "{count} deduções",
+  "credits-daily-deduction-count": "{count, plural, one {# dedução} other {# deduções}}",

-  "credits-daily-transaction-count": "{count} transações",
+  "credits-daily-transaction-count": "{count, plural, one {# transação} other {# transações}}",

Also applies to: 473-473

messages/es.json (1)

471-475: Make counters plural‑safe (ICU).

Use ICU plurals so “1 deducción / 1 transacción” render correctly.

-  "credits-daily-deduction-count": "{count} deducciones",
+  "credits-daily-deduction-count": "{count, plural, one {# deducción} other {# deducciones}}",
-  "credits-daily-transaction-count": "{count} transacciones",
+  "credits-daily-transaction-count": "{count, plural, one {# transacción} other {# transacciones}}",

Please confirm the i18n runtime supports ICU plural syntax (inlang message format).

messages/it.json (1)

470-474: Plural‑safe counters (ICU).

Ensure correct singular/plural for Italian.

-  "credits-daily-deduction-count": "{count} detrazioni",
+  "credits-daily-deduction-count": "{count, plural, one {# detrazione} other {# detrazioni}}",
-  "credits-daily-transaction-count": "{count} transazioni",
+  "credits-daily-transaction-count": "{count, plural, one {# transazione} other {# transazioni}}",

Confirm ICU plural support in the app’s i18n pipeline (inlang message format).

messages/hi.json (1)

469-469: Plural‑safe Hindi for deduction count (ICU).

Render “1 कटौती” vs “2 कटौतियाँ”.

-  "credits-daily-deduction-count": "{count} कटौतियाँ",
+  "credits-daily-deduction-count": "{count, plural, one {# कटौती} other {# कटौतियाँ}}",

Confirm ICU plural handling in the Hindi locale runtime.

messages/de.json (1)

377-466: Unify tone (Sie/Ihr) and avoid English–German hybrids in credits copy.

Current strings mix formal “Sie/Ihr” elsewhere with “du/dein” here, and use “Credit‑Guthaben/Credit‑Ablauffrist”. Suggest consistent formal tone and German terms.

Apply:

-  "credits-balance": "Credit-Guthaben",
+  "credits-balance": "Guthaben",
-  "credits-next-expiration": "Nächste Credit-Ablauffrist",
+  "credits-next-expiration": "Nächste Guthaben-Ablauffrist",
-  "credits-pricing-description": "Credits decken die Nutzung über die Grenzen deines Tarifs hinaus ab. Nutze diese Stufen, um abzuschätzen, wie viele du kaufen solltest.",
+  "credits-pricing-description": "Credits decken die Nutzung über die Grenzen Ihres Tarifs hinaus ab. Verwenden Sie diese Stufen, um abzuschätzen, wie viele Sie kaufen sollten.",
-  "credits-pricing-mau-subtitle": "Pro Gerät, das sich mindestens einmal im Monat meldet.",
+  "credits-pricing-mau-subtitle": "Pro Gerät, das sich mindestens einmal im Monat meldet.",
-  "credits-pricing-bandwidth-subtitle": "Pro GiB, das zusätzlich zu deinem Tarif ausgeliefert wird.",
+  "credits-pricing-bandwidth-subtitle": "Pro GiB, das zusätzlich zu Ihrem Tarif ausgeliefert wird.",
-  "credits-pricing-storage-subtitle": "Pro GiB, das Speicherplatz für deine Releases belegt.",
+  "credits-pricing-storage-subtitle": "Pro GiB, das Speicherplatz für Ihre Releases belegt.",
-  "credits-pricing-build-subtitle": "Pro Build-Minute, die über das in deinem Tarif enthaltene hinausgeht.",
+  "credits-pricing-build-subtitle": "Pro Build‑Minute, die über das in Ihrem Tarif enthaltene hinausgeht.",
-  "no-credits-available": "Noch keine Credits. Kaufe ein Paket, um dein Planlimit zu erweitern.",
+  "no-credits-available": "Noch keine Credits. Kaufen Sie ein Paket, um Ihr Tariflimit zu erweitern.",

Please also scan the remaining credits block for any lingering “dein/deinem/deines” and switch to “Ihr/Ihrem/Ihres” for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 382dfa5 and 38cf33e.

📒 Files selected for processing (20)
  • messages/de.json (2 hunks)
  • messages/en.json (2 hunks)
  • messages/es.json (2 hunks)
  • messages/fr.json (4 hunks)
  • messages/hi.json (2 hunks)
  • messages/id.json (2 hunks)
  • messages/it.json (2 hunks)
  • messages/ja.json (2 hunks)
  • messages/ko.json (2 hunks)
  • messages/pl.json (2 hunks)
  • messages/pt-br.json (2 hunks)
  • messages/ru.json (3 hunks)
  • messages/tr.json (2 hunks)
  • messages/vi.json (2 hunks)
  • messages/zh-cn.json (2 hunks)
  • supabase/migrations/20251125184322_add_top_up_credits_system.sql (1 hunks)
  • supabase/tests/00-supabase_test_helpers.sql (1 hunks)
  • supabase/tests/26_test_rls_policies.sql (2 hunks)
  • supabase/tests/32_test_usage_credits.sql (7 hunks)
  • supabase/tests/33_credit_usage_alerts.sql (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • supabase/tests/00-supabase_test_helpers.sql
🚧 Files skipped from review as they are similar to previous changes (1)
  • supabase/tests/33_credit_usage_alerts.sql
🧰 Additional context used
📓 Path-based instructions (2)
{supabase/functions/_backend/utils/postgress_schema.ts,supabase/migrations/**/*.sql}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Database schema must be defined in utils/postgress_schema.ts using Drizzle ORM and mirrored in SQL migrations

Files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
supabase/migrations/**/*.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/migrations/**/*.sql: Never edit previously committed migration files; create new migration files with supabase migration new <feature_slug> for schema changes
Run bun types after schema changes in migrations to regenerate TypeScript types for Supabase

supabase/migrations/**/*.sql: When a feature requires schema changes, create a single migration file with supabase migration new <feature_slug> and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, treating that seeding as part of the current feature and not modifying previously committed migrations
Do not create new cron jobs; instead update the process_all_cron_tasks function in a new migration file to add your job if needed

Files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
🧠 Learnings (8)
📚 Learning: 2025-12-05T17:34:36.569Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T17:34:36.569Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • supabase/tests/26_test_rls_policies.sql
  • supabase/tests/32_test_usage_credits.sql
  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:12.533Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-05T17:34:12.533Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` with new or changed test fixtures when adding database schema changes

Applied to files:

  • supabase/tests/26_test_rls_policies.sql
  • supabase/tests/32_test_usage_credits.sql
  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:36.569Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T17:34:36.569Z
Learning: Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Applied to files:

  • supabase/tests/32_test_usage_credits.sql
📚 Learning: 2025-12-05T17:34:36.569Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T17:34:36.569Z
Learning: Applies to supabase/migrations/**/*.sql : A migration that introduces a new table may include seed inserts for that table, treating that seeding as part of the current feature and not modifying previously committed migrations

Applied to files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:36.569Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T17:34:36.569Z
Learning: Applies to supabase/migrations/**/*.sql : Do not create new cron jobs; instead update the `process_all_cron_tasks` function in a new migration file to add your job if needed

Applied to files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:12.533Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-05T17:34:12.533Z
Learning: Applies to supabase/migrations/**/*.sql : Never edit previously committed migration files; create new migration files with `supabase migration new <feature_slug>` for schema changes

Applied to files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:36.569Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T17:34:36.569Z
Learning: Applies to supabase/migrations/**/*.sql : When a feature requires schema changes, create a single migration file with `supabase migration new <feature_slug>` and keep editing that file until the feature ships; never edit previously committed migrations

Applied to files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
📚 Learning: 2025-12-05T17:34:12.533Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-05T17:34:12.533Z
Learning: Applies to supabase/functions/_backend/**/*.ts : Use `getRightKey()` from `scripts/utils.mjs` to access environment-specific configuration values; never hard-code URLs or environment-specific values

Applied to files:

  • supabase/migrations/20251125184322_add_top_up_credits_system.sql
⏰ 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). (2)
  • GitHub Check: Run tests
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (20)
messages/pl.json (1)

1-1055: Duplicate key issue from previous review has been resolved — no action required.

All locale files now contain exactly 1053 unique keys with no duplicates. The critical structural issue flagged in the previous review (duplicate "filter-actions" and "credits-balance" keys) has been successfully fixed across pl.json and all related locale files (de.json, it.json, ja.json, ko.json, ru.json, tr.json, zh-cn.json). JSON validation confirms valid structure and consistency.

supabase/tests/26_test_rls_policies.sql (2)

6-6: Plan count updated correctly for new tests.

Updated from 35 to 37 to account for the two new assertions on usage_credit_ledger. The increment is correct.


298-322: Robust RLS and security_invoker assertions for usage_credit_ledger.

The two new test assertions are well-designed:

  • Lines 300–305 verify that the authenticated role has SELECT privilege on usage_credit_ledger.
  • Lines 307–322 verify the view is configured with security_invoker by querying pg_class.reloptions using a flexible LIKE 'security_invoker%' pattern. This correctly handles PostgreSQL's storage of view options as "keyword=value" strings.

The approach is sound and more robust than exact-match checks.

supabase/tests/32_test_usage_credits.sql (5)

33-42: Test verifies source_ref disambiguation in top_up_usage_credits.

Validates that the function definition includes the qualified column reference t.source_ref to avoid ambiguity in the unique_violation exception handler. This is a good regression test that prevents future refactors from inadvertently breaking the function's idempotency logic.


44-153: Test setup pattern correctly uses temp tables and CTEs for data persistence.

The reorganized setup now properly chains CTEs and materializes results into a temporary table (test_credit_context). This avoids the CTE scope issue flagged in the previous review—CTEs are defined within their WITH block and cannot be referenced in subsequent top-level statements, so persisting to a temp table and querying from it later is the correct approach.

The dependency chain (plan → user → stripe_info → org → grant → step) is sound, with each CTE providing columns needed by subsequent CTEs.


155-177: Constraint validation test correctly uses throws_ok.

Tests that the source column check constraint on usage_credit_grants properly rejects invalid values (e.g., 'invalid_source'). The expected error message matches PostgreSQL's constraint violation format.


305-384: Comprehensive concurrency and idempotency tests for top_up_usage_credits.

Three assertions verify the critical idempotency guarantees:

  • Duplicate RPC calls with identical source_ref return the same transaction_id (lines 346–357).
  • Duplicate calls return the same grant_id (lines 359–370).
  • Only one purchase transaction row is created in the database (lines 372–384).

This is excellent coverage for a payment-related function. The test isolates and validates the function's deduplication behavior, which is essential for preventing double-charging.


554-717: Ledger view CTE setup correctly chains dependencies and uses temp table persistence.

The nested CTE structure (setup → context_insert → grant_one/two → overage → consumptions → deductions) properly chains inserts and returns. The final SELECT 1 statement executes the entire CTE block, ensuring all side effects (inserts) are committed.

Later assertions (lines 719–743) correctly reference the persisted test_usage_ledger_context temp table to validate ledger aggregation behavior (collapsing multiple grant deductions per overage event into one ledger row, with correct aggregated amounts).

supabase/migrations/20251125184322_add_top_up_credits_system.sql (7)

3-13: Simplified credit_id approach in plans table.

Adds credit_id column directly to plans rather than using a separate configuration table. This is cleaner than the earlier capgo_credit_products table approach and addresses the hardcoding concern from the prior review by centralizing the product ID on the plan itself.

The default value is set to a test Stripe product ID (prod_TJRd2hFHZsBIPK), which is safe for a development/test default. Ensure seed or configuration management handles production product IDs appropriately.


17-44: Defensive DO block safely adds source constraint.

Validates and enforces the source check constraint on usage_credit_grants, updating any invalid/null values to the fallback 'manual' before adding the constraint. The approach:

  • Detects if constraint already exists (avoids errors on re-runs)
  • Coalesces invalid values to a safe default
  • Uses format() to safely construct the constraint definition

Defensive programming well-applied for a production migration.


46-190: top_up_usage_credits function correctly implements security and idempotency.

Security posture is sound:

  • SECURITY DEFINER allows the function to execute with elevated privileges (required for writes to credit tables from frontend context).
  • SET search_path = '' mitigates search_path injection.
  • Role validation (line 82) restricts execution to postgres or service_role only.
  • Input validation on org_id, amount (lines 86–92).

Idempotency via subtransaction (lines 97–179):

  • Wraps grant/transaction inserts in a subtransaction to catch unique_violation.
  • Exception handler looks up the existing transaction by sessionId or paymentIntentId (lines 153–163).
  • If found, returns the existing grant and transaction instead of creating duplicates.
  • If not found, re-raises the exception (could indicate a different constraint violation).

This is a solid pattern for handling Stripe checkout idempotency (same session/payment intent → same grant/transaction).


205-267: Unique indexes on source_ref fields prevent duplicate purchases.

The DO block creates conditional unique indexes on source_ref->>'sessionId' and source_ref->>'paymentIntentId':

  • Pre-checks for existing duplicates (lines 217–245) to avoid migration failure.
  • Indexes are conditional: WHERE transaction_type = 'purchase' AND source_ref->>'key' IS NOT NULL.
  • Allows nulls and non-purchase transaction types to avoid over-constraining.

This is an excellent design—it prevents future duplicate purchases via database constraints while remaining flexible for other transaction types and edge cases.


469-619: usage_credit_ledger view correctly aggregates deductions with security_invoker.

The view is defined with security_invoker = true and security_barrier = true, enforcing RLS policies on underlying tables. The complex CTE logic:

  • overage_allocations: Groups consumptions by overage event and aggregates grant allocations.
  • aggregated_deductions: Collapses multiple deductions for the same overage event into one ledger row, summing amounts and preserving grant allocation details.
  • other_transactions: Passes through purchase, expiry, and other non-deduction transactions unmodified.
  • UNION ALL: Combines both branches.

The view correctly implements the ledger requirement: multiple deductions against different grants for the same overage event are consolidated into a single aggregated row in the ledger, reducing clutter while preserving full audit detail via the grant_allocations JSONB field.


625-701: Credit usage alert trigger correctly enqueues at threshold crossings.

The enqueue_credit_usage_alert() function fires on INSERT and:

  • Ignores non-negative amounts (only alerts on deductions) (line 642).
  • Calculates the percent used before and after the transaction (lines 664–665).
  • Enqueues alerts only when crossing predefined thresholds (50%, 75%, 90%, 100%) (lines 669–689).
  • Uses alert_cycle = year*100 + month to reset alerts monthly (line 667).

The logic correctly prevents alert spam (one alert per threshold per cycle) while capturing the critical usage milestones. Integration with process_all_cron_tasks (line 727) ensures alerts are processed frequently (every 10 seconds).


704-890: process_all_cron_tasks orchestrates all scheduled jobs with proper error isolation.

The function schedules tasks at multiple cadences (every 10 seconds, every minute, every 5 minutes, hourly, every 2 hours, every 6 hours, and daily). Key observations:

  • Each task is wrapped in its own BEGIN...EXCEPTION WHEN OTHERS THEN block, ensuring failures do not cascade.
  • credit_usage_alerts is processed every 10 seconds in the high-frequency queue (line 727), consistent with the alert trigger (line 699).
  • Credit expiry (expire_usage_credits) is processed daily at 3 AM (line 848).
  • Task scheduling uses UTC time components (EXTRACT) to ensure consistency.

The error isolation and frequent polling of credit alerts ensures timely delivery without blocking other jobs.

messages/en.json (2)

2-2: ✓ Schema URL correctly updated to inlang-message-format.

The Inlang message format is a simple storage plugin that stores simple messages in a JSON file per language using key-value pairs. The schema reference is now correct.


362-472: ✓ Comprehensive credits system translations added with proper structure.

All 111 new credits-related keys (transactions, pricing tiers, UI labels, top-up flow) are properly formatted:

  • credit-transaction-* keys (11 entries) for ledger/transaction display
  • credits-pricing-* keys with MAU, bandwidth, storage, and build-time tier pricing
  • credits-* keys for UI states (empty, loading, CTA, balance display, pagination)
  • credits-top-up-* and credits-daily-* keys for checkout and activity tracking
  • buy-credits and plan-* keys for primary CTA and plan information

All variable placeholders ({amount}, {current}, {total}, {count}, {metric}, {hours}) are correctly formatted. Terminology aligns with Capgo's usage model (MAU = Monthly Active Users, GiB = storage, etc.).

messages/fr.json (3)

2-2: ✓ Schema URL correctly updated to match en.json.

The schema reference is now aligned with the English file and the current Inlang standard.


359-472: ✓ All 111 credits keys now properly translated to French (resolves past critical issue).

Previous reviews flagged that the build-time pricing section (lines 382–395 in the old version) remained in English. This critical issue is now resolved:

  • Build-time pricing (lines 444–457): Properly translated with French terminology
    • "Temps de build (minutes)" for the title
    • "$0.50 par minute" for pricing (correctly localized currency format)
    • All 12 build-time tier entries translated
  • MAU, bandwidth, and storage pricing sections verified as complete with French translations
  • Top-up flow and transaction keys translated consistently
  • Placeholder syntax preserved: e.g., {amount}, {current}, {count} remain intact

French terminology is idiomatic and consistent with standard SaaS localization conventions. No untranslated English fragments remain.


460-460: No action needed — duplicate key issue is already resolved.

Verification confirms no duplicate keys exist in either en.json or fr.json, and perfect parity is maintained across both files with 130 credits-related keys present in each. The concern flagged in past reviews has been addressed.

Comment on lines 377 to 389
"created-at": "Creado en",
"credits-available": "Créditos disponibles",
"credits": "Créditos",
"credits-cta-description": "Compra créditos de uso adicionales al instante y mantén a tus usuarios recibiendo actualizaciones sin interrupciones.",
"credits-cta-title": "¿Necesitas más créditos?",
"credits-empty-state": "Aún no hay transacciones de créditos.",
"credits-load-error": "No pudimos cargar tu historial de créditos. Inténtalo de nuevo.",
"credits-transactions": "Transacciones de créditos",
"credits-used-in-period": "Créditos utilizados en el período",
"credits-used-dollars": "Créditos utilizados (USD)",
"credits-used-dollars-description": "Valor estimado en dólares de los créditos consumidos durante el período de facturación actual.",
"credits-balance": "Saldo de créditos",
"credits-available": "Créditos disponibles",
"credits-next-expiration": "Próximo vencimiento de créditos",
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.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# List files in messages directory to understand locale structure
git ls-files messages/ | head -20

Repository: Cap-go/capgo

Length of output: 335


🏁 Script executed:

# Check if messages/es.json exists and verify its content around lines 377-389
if [ -f messages/es.json ]; then
  wc -l messages/es.json
  sed -n '377,389p' messages/es.json
fi

Repository: Cap-go/capgo

Length of output: 953


🏁 Script executed:

# Search for the keys mentioned in the script to see if they exist
rg "credits-top-up-total-estimate|credits-daily-deduction-title|credits-daily-deduction-count|credits-pagination-label|credits-daily-transaction-count" messages/

Repository: Cap-go/capgo

Length of output: 5943


🏁 Script executed:

# Check for actual duplicate keys in all locale JSON files
for f in messages/*.json; do
  python3 - <<'PY' "$f"
import json, sys
try:
  with open(sys.argv[1], 'r', encoding='utf-8') as file:
    data = json.load(file)
  # Check if any keys are duplicated by reading with object_pairs_hook
  seen = set()
  duplicates = []
  with open(sys.argv[1], 'r', encoding='utf-8') as file:
    content = file.read()
    import re
    keys = re.findall(r'"([^"]+)"\s*:', content)
    for k in keys:
      if k in seen:
        duplicates.append(k)
      seen.add(k)
  if duplicates:
    print(f"{sys.argv[1]}: Duplicates found: {duplicates}")
  else:
    print(f"{sys.argv[1]}: OK")
except Exception as e:
  print(f"{sys.argv[1]}: Error - {e}")
PY
done

Repository: Cap-go/capgo

Length of output: 403


🏁 Script executed:

# Verify JSON validity and check if all locale files are valid JSON
for f in messages/*.json; do
  python3 -m json.tool "$f" > /dev/null 2>&1 && echo "$f: Valid JSON" || echo "$f: Invalid JSON"
done

Repository: Cap-go/capgo

Length of output: 496


Add translation QA checks to catch duplicate keys and placeholder drift.

The locale files contain at least one duplicate key (general in messages/pt-br.json) that would be caught by the proposed checks. Implementing duplicate key detection and placeholder validation across all locales (messages/*.json) will prevent similar issues in future translations.

🤖 Prompt for AI Agents
In messages/es.json around lines 377 to 389, the review notes missing QA checks
that allow duplicate translation keys and placeholder drift across locale files;
add a validation step that scans all messages/*.json to (1) detect duplicate
keys within each file (fail CI on duplicates), (2) ensure every locale has the
same key set as the canonical locale (e.g., messages/en.json) and report
missing/extra keys, and (3) validate placeholder tokens (e.g., {name}, %s) match
exactly between each translation and the canonical string; implement this as a
small node script or use an existing linter, wire it into CI to fail on
violations, and run it once to identify and fix the existing
duplicate/placeholder issues (then correct the locale files accordingly).

Comment on lines +382 to 385
"credits-used-in-period": "Số điểm đã sử dụng trong kỳ",
"credits-used-dollars": "Tín dụng đã dùng (USD)",
"credits-used-dollars-description": "Giá trị đô la ước tính của số tín dụng đã sử dụng trong kỳ thanh toán hiện tại.",
"credits-balance": "Số dư tín dụng",
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.

⚠️ Potential issue | 🟡 Minor

Use “tín dụng” consistently.

Avoid mixing “điểm” with “tín dụng” in the credits surface.

-  "credits-used-in-period": "Số điểm đã sử dụng trong kỳ",
+  "credits-used-in-period": "Tín dụng đã dùng trong kỳ",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"credits-used-in-period": "Số điểm đã sử dụng trong kỳ",
"credits-used-dollars": "Tín dụng đã dùng (USD)",
"credits-used-dollars-description": "Giá trị đô la ước tính của số tín dụng đã sử dụng trong kỳ thanh toán hiện tại.",
"credits-balance": "Số dư tín dụng",
"credits-used-in-period": "Tín dụng đã dùng trong kỳ",
"credits-used-dollars": "Tín dụng đã dùng (USD)",
"credits-used-dollars-description": "Giá trị đô la ước tính của số tín dụng đã sử dụng trong kỳ thanh toán hiện tại.",
"credits-balance": "Số dư tín dụng",
🤖 Prompt for AI Agents
messages/vi.json around lines 382 to 385: the translation for
"credits-used-in-period" uses "Số điểm đã sử dụng trong kỳ" which mixes "điểm"
with "tín dụng"; change it to use "tín dụng" consistently (e.g., "Số tín dụng đã
sử dụng trong kỳ"), and review the surrounding keys to ensure all credit-related
strings use "tín dụng" instead of "điểm".

@Dalanir
Copy link
Copy Markdown
Contributor Author

Dalanir commented Dec 9, 2025

Events for bento alerts email:

const EVENT_BY_THRESHOLD: Record<number, string> = {
50: 'org:credits_usage_50_percent',
75: 'org:credits_usage_75_percent',
90: 'org:credits_usage_90_percent',
100: 'org:credits_usage_100_percent',
}

@riderx riderx merged commit 71138aa into main Dec 12, 2025
8 of 9 checks passed
@riderx riderx deleted the credits-top-up-dashboard branch December 12, 2025 08:18
@sonarqubecloud
Copy link
Copy Markdown

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants