From 9d0f43780b4eed177037cc26559ac69e8dad74a4 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Mon, 5 Oct 2026 16:15:56 +0000 Subject: [PATCH] feat: provision onboarding-complete reviewer workspaces with expiring Test access, bounded credits and Test header labels Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- admin/src/app/dashboard/OrganizationsPage.tsx | 1 + admin/src/app/dashboard/TestersPage.tsx | 7 +- admin/src/lib/api/models/admin.ts | 1 + .../docs/development/accounts-and-access.mdx | 10 +- docs/content/docs/guides/ai-credits.mdx | 2 + docs/content/docs/guides/billing.mdx | 2 + .../docs/guides/workspace-export-import.mdx | 2 + internal/api/handler/admin_tester.go | 7 +- internal/api/handler/admin_tester_test.go | 92 ++++++++ internal/app/feature/gate_tester_test.go | 41 ++++ .../create_tester_workspace_test.go | 49 +++++ internal/app/organization/service.go | 22 ++ internal/app/orgtransfer/export_test.go | 6 + internal/app/orgtransfer/import.go | 1 + internal/app/user/user.go | 3 +- internal/app/user/user_cache_live_test.go | 54 +++++ internal/config/inbox_test.go | 14 ++ .../000264_tester_workspaces.down.sql | 8 + .../000264_tester_workspaces.up.sql | 58 +++++ internal/models/admin.go | 21 +- internal/models/organization.go | 22 +- internal/models/subscriptions.go | 2 + internal/repository/pg_organization.go | 17 +- internal/repository/pg_tester_workspace.go | 59 +++++ internal/repository/pg_user.go | 25 ++- .../repository/tester_workspace_live_test.go | 207 ++++++++++++++++++ web/src/components/layout/CreditsMeter.tsx | 15 +- web/src/components/layout/PlanPill.tsx | 13 ++ .../components/layout/TesterHeader.test.tsx | 75 +++++++ web/src/hooks/useFeatureAccess.ts | 6 +- .../app/organizations/getOrganizations.ts | 2 + .../models/app/organizations/Organization.ts | 1 + web/src/lib/plans.ts | 2 + web/src/stores/slices/organizationSlice.ts | 1 + 34 files changed, 796 insertions(+), 52 deletions(-) create mode 100644 internal/api/handler/admin_tester_test.go create mode 100644 internal/app/feature/gate_tester_test.go create mode 100644 internal/app/organization/create_tester_workspace_test.go create mode 100644 internal/app/user/user_cache_live_test.go create mode 100644 internal/infrastructure/db/migrations/000264_tester_workspaces.down.sql create mode 100644 internal/infrastructure/db/migrations/000264_tester_workspaces.up.sql create mode 100644 internal/repository/pg_tester_workspace.go create mode 100644 internal/repository/tester_workspace_live_test.go create mode 100644 web/src/components/layout/TesterHeader.test.tsx diff --git a/admin/src/app/dashboard/OrganizationsPage.tsx b/admin/src/app/dashboard/OrganizationsPage.tsx index f35518376..cb6ece32a 100644 --- a/admin/src/app/dashboard/OrganizationsPage.tsx +++ b/admin/src/app/dashboard/OrganizationsPage.tsx @@ -76,6 +76,7 @@ const columns: Column[] = [ > {o.name} + {o.category === "test" && Test} {o.slug &&
{o.slug}
} ), diff --git a/admin/src/app/dashboard/TestersPage.tsx b/admin/src/app/dashboard/TestersPage.tsx index 79bd855df..d530757e7 100644 --- a/admin/src/app/dashboard/TestersPage.tsx +++ b/admin/src/app/dashboard/TestersPage.tsx @@ -141,9 +141,10 @@ export default function TestersPage() { description={ <> Accounts for people outside the team. Each skips the emailed login code, because the - holder cannot read this instance's mail. Everything else still applies: the password, + holder cannot read this instance's mail, and arrives with onboarding complete. Authentication still requires the password, the captcha and the sign-in risk assessment. A tester either gets a workspace of its own - or joins one that already exists. Its password stops working on the date you choose, and + or joins one that already exists. A new Test workspace includes paid-feature access and 100 test credits until the password expires. + An existing workspace keeps its plan and the role you select. Its password stops working on the date you choose, and revoking it ends the password and signs out every session at once. } @@ -160,7 +161,7 @@ export default function TestersPage() {
{created.joined_existing ? "This account is a member of an existing workspace and will land in it on sign-in." - : "This account owns a new, empty workspace."} + : "This account owns a new Test workspace with paid-feature access and 100 test credits until the password expires."}