feat(web): add sales-demo organizations with admin create and reset - #5459
Merged
Conversation
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (8 files)
Previous Review Summaries (4 snapshots, latest commit 60682cb)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 60682cb)Status: 2 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (28 files)
Previous review (commit 4074c19)Status: 3 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (28 files)
Previous review (commit ab4c233)Status: 8 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (28 files)
Previous review (commit a39c67a)Status: 8 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (28 files)
Reviewed by grok-4.6 · Input: 101.8K · Output: 14.9K · Cached: 697.3K Review guidance: REVIEW.md from base branch |
Serialize resets with a row lock, disable auto top-up, and clear pending invitations so a reset demo is clean.
Demo orgs already appear on the paying list; stop them also matching the trial filter.
Render the error card on org-query failure instead of silently returning null.
Reset state on any close and use an email-literal-guardrail-safe placeholder.
IS DISTINCT FROM 'true' keeps ordinary orgs whose settings lack the key.
pandemicsyn
approved these changes
Aug 25, 2026
pandemicsyn
left a comment
Contributor
There was a problem hiding this comment.
few inline from the bot
# Conflicts: # packages/db/src/migrations/meta/0224_snapshot.json # packages/db/src/migrations/meta/_journal.json
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@kilocode.aiand@anaconda.comaddresses qualify.The organization settings schema gains
is_sales_demoandsales_demo_last_reset_at, and the organizations table gains a partial unique indexUQ_organizations_live_sales_demo_per_ownerso an owner can hold one live demo. A new non-self-service credit categorysales-demofunds the $50 grant, so it never appears as a user-redeemable promo code. Existing organizations carry neither settings field, so the absent key reads as not-a-demo and no stored row changes.Files
packages/db/src/schema.ts— adds the partial unique index oncreated_by_kilo_user_idwhereis_sales_demois true anddeleted_atis null.packages/db/src/schema-types.ts— addsis_sales_demoandsales_demo_last_reset_atto the organization settings schema.apps/web/src/lib/promoCreditCategories.ts— registers the non-self-servicesales-democredit category.createSalesDemoOrganizationinserts the enterprise demo organization, seeds the owner plus 25 stable demo members, and grants a $50sales-democredit; it throwsALREADY_OWNS_DEMOwhen the owner already has a live demo, caught after a pre-check and again after theonConflictDoNothinginsert.restoreSalesDemoOrganizationclears usage, credit, invitation, and daily-usage rows, zeroes balances, disables auto top-up, re-seeds the owner plus 25 members, and re-grants $50 under aFOR UPDATErow lock; it throwsNOT_LIVE_SALES_DEMOfor any organization that is not a live demo. Demo settings disable usage limits and trial messaging and storesales_demo_last_reset_at.Files
apps/web/src/lib/organizations/sales-demo.ts— create and restore transactions; clearsmicrodollar_usage,exa_usage_log,compute_usage_charge,credit_transactions,organization_invitations,organization_user_usage, andmicrodollar_usage_daily; re-seeds and re-grants; defines both sentinels.Two admin procedures
salesDemo.createandsalesDemo.resetwrap the lifecycle over tRPC. Create returnsBAD_REQUESTfor a non-allowlisted email,NOT_FOUNDfor an unknown owner, andCONFLICTwhose message packs the live demo id and name; reset mapsNOT_LIVE_SALES_DEMOtoNOT_FOUND. The allowlist lives in a module free of server-only imports so the dialog and the router share one rule.Files
apps/web/src/routers/admin/sales-demo-router.ts—salesDemo.createandsalesDemo.resetmutations and their error mapping.apps/web/src/lib/organizations/sales-demo-email.ts— shared allowlist domain matcher.apps/web/src/routers/admin-router.ts— mountssalesDemoon the admin router.The cron route
GET /api/cron/sales-demo-resetresets every live demo organization and answers{reset, failed}. It requires aBearerCRON_SECRET, skips an organization whose owner is missing, and reports failures to Sentry without aborting the sweep. Vercel invokes it daily at0 5 * * *.Files
apps/web/src/app/api/cron/sales-demo-reset/route.ts— cron handler that iterates live demos and returns reset and failed counts.apps/web/vercel.json— adds the/api/cron/sales-demo-resetcron entry.The admin organization list now treats sales-demo organizations as
payingand removes them fromtrial, and demo organizations bypass any Stripe-status filter. The trial exclusion usesIS DISTINCT FROM 'true'so an absent settings key cannot leak a demo into the trial list; the paying and Stripe-status inclusions match= 'true'.Files
apps/web/src/routers/organizations/organization-admin-router.ts— mode filters and Stripe-status inclusions for sales-demo organizations.Sign-in landing, the disabled-personal-account landing, the profile organization list, and the client sidebar choose a live sales-demo organization before the oldest. A shared
compareOrganizationsForDefaultcomparator and anisSalesDemoprojection drive the ordering, so the server redirect and the sidebar agree.Files
apps/web/src/lib/organizations/sales-demo-sort.ts— shared default-selection comparator; a sales-demo organization always wins.apps/web/src/lib/user/server.ts— demo-first landing and disabled-account routing via the shared comparator.apps/web/src/lib/organizations/organizations.ts— exposesisSalesDemoand ordersgetProfileOrganizationsdemo-first.apps/web/src/lib/organizations/organization-types.ts— addsisSalesDemotoUserOrganizationWithSeats.apps/web/src/app/(app)/components/AppSidebar.tsx— sorts the default organization with the shared comparator.The admin organizations page gains a create-demo dialog, and the admin detail page gains a reset card that renders only for demo organizations. The organizations table takes an
actionsslot so the page passes the dialog trigger without the table knowing the dialog.Files
apps/web/src/app/admin/components/CreateDemoOrganizationDialog.tsx— create form, client email validation, and the conflict link to the existing demo.apps/web/src/app/admin/components/OrganizationAdmin/OrganizationAdminSalesDemoReset.tsx— reset confirm dialog, hidden for non-demos.apps/web/src/app/admin/components/OrganizationsTable.tsx— adds theactionsslot.apps/web/src/app/admin/organizations/page.tsx— passes the create-demo button.apps/web/src/app/admin/components/OrganizationAdmin/OrganizationAdminDashboard.tsx— renders the reset card.The demo organization home hides the welcome banner and the seat usage card. Seat usage now returns nothing while the organization query loads, surfaces an error card when that query fails, and hides for a suppressed-trial or sales-demo organization before any seat-usage loading or error state.
Files
apps/web/src/components/organizations/OrganizationDashboard.tsx— skips the welcome banner for sales-demo organizations.apps/web/src/components/organizations/SeatUsageCard.tsx— hides for suppressed-trial and sales-demo organizations; adds an organization-error card and drops the pre-organization loading card.Tests: 8 test files changed (6 added, 2 updated).
Generated: 3 files —
0225_rare_captain_britain.sql,0225_snapshot.json, and an updated_journal.json.Verification
The web platform ran the six scenarios across five rounds, web-r1 through web-r4-cont.
The rounds reproduced no defect on the unfixed build; every case passed on head 902f351.
No recording exists.
Visual Changes
Admin organization list. The list header now holds a Create Demo Organization button in the primary yellow fill. In the picture, the button sits at the top right of the page, above the organization rows.
Admin organization detail. The detail now holds a Reset demo organization card in the credit column, and a reset restores the baseline. In the picture, the reset card sits in the right column below Nullify Credits, and the balance reads $50.00.
Create dialog, conflict state. A second create for an existing owner now shows an inline link to the live demo organization instead of a toast or navigation. In the picture, the dialog stays open, the Email field keeps the address, and the yellow org-name link wraps to two lines below the field.
Demo organization home. The owner home now shows the balance and the member list with no Seat Usage card. In the picture, the $50.00 balance card and the Members (26) list sit at the top, and no Seat Usage card appears on the page.
Human Steps
No human steps required.
Reviewer Notes
None.