Skip to content

Free tier and request workspaces#577

Merged
spashii merged 5 commits into
mainfrom
free-tier-and-request-workspaces
May 15, 2026
Merged

Free tier and request workspaces#577
spashii merged 5 commits into
mainfrom
free-tier-and-request-workspaces

Conversation

@ussaama
Copy link
Copy Markdown
Contributor

@ussaama ussaama commented May 14, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced free tier as default for new users with 1-hour lifetime cap
    • Added staff-reviewed workspace request workflow replacing self-serve creation
    • Implemented over-capacity handling via transcript locking instead of hard recording blocks
    • Added tier expiration with 3-day pre-warning notifications
    • Unified guest and member seat capacity into single pool
    • Added admin approval/denial interface for upgrade requests
  • Documentation

    • Added comprehensive implementation plan and test strategy for free tier initiative

Review Change Stack

ussaama added 4 commits May 13, 2026 16:07
- Add workspace_request flow (Directus + API), admin approve/deny, and email templates
- Default new workspaces to free tier; tier expiry/pre-warning scheduling and notifications
- Enforce seat/tier limits with over-cap stamping, locked transcript/upload UI, and chat link gating
- Introduce staff email throttling and digest templates; extend notifications and Dramatiq tasks
- Rename workspace visibility open_to_team → open_to_organisation across schema and app
- Expand admin/workspace settings, onboarding, org BFF, and tier capacity logic; add tests
…ng invite visibility

  - UpgradeModal: let users pick a target tier via SegmentedControl instead of auto-selecting the minimum required tier
  - Workspace request history endpoint + UI on the billing tab so members can track their upgrade/new-workspace requests
  - Pending workspace requests shown as dashed cards on /w selector
  - Pending invites section on the org page (admin-only)
  - Upload gating in ConversationAccordion when workspace hits cap
  - Locked transcript overlay + audio download gating on over-cap conversations
  - recalculate_over_cap_on_upgrade clears stale stamps after tier upgrade
  - apply_downgrade_effects clears is_over_cap so pre-downgrade content stays readable
  - Progress bar colors shift yellow at 60% and red at 90% usage
  - Hardcoded blue/green colors replaced with primary theme token
…lish

  Replace client-side email pre-check with a server-side registration
  proxy that always returns 204, sending a sign-in nudge email to
  existing accounts instead of leaking enrollment status. Remove the
  orphaned /check-email endpoint. Improve locked conversation overlays
  with transcript/summary variants and refine upload-locked button copy.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Warning

Rate limit exceeded

@ussaama has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 51 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 349db783-8cc8-4177-9f29-31f8371b201a

📥 Commits

Reviewing files that changed from the base of the PR and between cd7adbd and 1c9b776.

📒 Files selected for processing (144)
  • echo/directus/sync/collections/settings.json
  • echo/directus/sync/snapshot/collections/workspace_request.json
  • echo/directus/sync/snapshot/fields/conversation/is_over_cap.json
  • echo/directus/sync/snapshot/fields/workspace/percent_discount.json
  • echo/directus/sync/snapshot/fields/workspace/pre_warning_sent.json
  • echo/directus/sync/snapshot/fields/workspace/tier.json
  • echo/directus/sync/snapshot/fields/workspace/tier_expires_at.json
  • echo/directus/sync/snapshot/fields/workspace/type_discount.json
  • echo/directus/sync/snapshot/fields/workspace/visibility.json
  • echo/directus/sync/snapshot/fields/workspace_request/created_at.json
  • echo/directus/sync/snapshot/fields/workspace_request/decided_at.json
  • echo/directus/sync/snapshot/fields/workspace_request/decided_by.json
  • echo/directus/sync/snapshot/fields/workspace_request/denial_reason.json
  • echo/directus/sync/snapshot/fields/workspace_request/granted_percent_discount.json
  • echo/directus/sync/snapshot/fields/workspace_request/granted_tier.json
  • echo/directus/sync/snapshot/fields/workspace_request/granted_tier_expires_at.json
  • echo/directus/sync/snapshot/fields/workspace_request/granted_type_discount.json
  • echo/directus/sync/snapshot/fields/workspace_request/id.json
  • echo/directus/sync/snapshot/fields/workspace_request/kind.json
  • echo/directus/sync/snapshot/fields/workspace_request/org_id.json
  • echo/directus/sync/snapshot/fields/workspace_request/proposed_name.json
  • echo/directus/sync/snapshot/fields/workspace_request/proposed_tier.json
  • echo/directus/sync/snapshot/fields/workspace_request/proposed_visibility.json
  • echo/directus/sync/snapshot/fields/workspace_request/requested_by.json
  • echo/directus/sync/snapshot/fields/workspace_request/requester_message.json
  • echo/directus/sync/snapshot/fields/workspace_request/resulting_workspace_id.json
  • echo/directus/sync/snapshot/fields/workspace_request/staff_notes.json
  • echo/directus/sync/snapshot/fields/workspace_request/status.json
  • echo/directus/sync/snapshot/fields/workspace_request/updated_at.json
  • echo/directus/sync/snapshot/fields/workspace_request/workspace_id.json
  • echo/directus/sync/snapshot/relations/workspace_request/decided_by.json
  • echo/directus/sync/snapshot/relations/workspace_request/org_id.json
  • echo/directus/sync/snapshot/relations/workspace_request/requested_by.json
  • echo/directus/sync/snapshot/relations/workspace_request/resulting_workspace_id.json
  • echo/directus/sync/snapshot/relations/workspace_request/workspace_id.json
  • echo/docs/adr/0001-over-cap-conversation-model.md
  • echo/docs/issues/free-tier-and-request-workspaces/01-free-tier-in-matrix.md
  • echo/docs/issues/free-tier-and-request-workspaces/02-onboarding-seeds-free.md
  • echo/docs/issues/free-tier-and-request-workspaces/03-usage-gates-exposed.md
  • echo/docs/issues/free-tier-and-request-workspaces/04-is-over-cap-stamp.md
  • echo/docs/issues/free-tier-and-request-workspaces/05-live-locked-gate-overlay.md
  • echo/docs/issues/free-tier-and-request-workspaces/06-host-upload-gating.md
  • echo/docs/issues/free-tier-and-request-workspaces/07-chat-link-gating.md
  • echo/docs/issues/free-tier-and-request-workspaces/08-workspace-request-submission.md
  • echo/docs/issues/free-tier-and-request-workspaces/09-admin-upgrades-page.md
  • echo/docs/issues/free-tier-and-request-workspaces/10-approve-action.md
  • echo/docs/issues/free-tier-and-request-workspaces/11-deny-action.md
  • echo/docs/issues/free-tier-and-request-workspaces/12-request-notifications-emails.md
  • echo/docs/issues/free-tier-and-request-workspaces/13-staff-notification-batching.md
  • echo/docs/issues/free-tier-and-request-workspaces/14-tier-upgrade-kind.md
  • echo/docs/issues/free-tier-and-request-workspaces/15-tier-expires-at-cron.md
  • echo/docs/issues/free-tier-and-request-workspaces/16-tier-expiring-soon-prewarning.md
  • echo/docs/issues/free-tier-and-request-workspaces/17-guest-unification-backend.md
  • echo/docs/issues/free-tier-and-request-workspaces/18-guest-unification-frontend.md
  • echo/docs/issues/free-tier-and-request-workspaces/19-discount-fields.md
  • echo/docs/plans/free-tier-and-request-workspaces.md
  • echo/docs/plans/free-tier-test-plan.md
  • echo/docs/prds/free-tier-and-request-workspaces.md
  • echo/frontend/src/components/auth/hooks/index.ts
  • echo/frontend/src/components/conversation/ConversationAccordion.tsx
  • echo/frontend/src/components/conversation/ConversationChunkAudioTranscript.tsx
  • echo/frontend/src/components/conversation/ConversationDangerZone.tsx
  • echo/frontend/src/components/conversation/LockedTranscriptOverlay.tsx
  • echo/frontend/src/components/organisation/OrganisationCapBanner.tsx
  • echo/frontend/src/components/organisation/OrganisationInviteWizard.tsx
  • echo/frontend/src/components/project/ProjectSidebar.tsx
  • echo/frontend/src/components/project/ProjectUploadSection.tsx
  • echo/frontend/src/components/project/UploadLockedCard.tsx
  • echo/frontend/src/components/workspace/FeatureGate.tsx
  • echo/frontend/src/components/workspace/OrganisationProjectsTable.tsx
  • echo/frontend/src/components/workspace/OrganisationUsageRollup.tsx
  • echo/frontend/src/components/workspace/SeatCapBanner.tsx
  • echo/frontend/src/components/workspace/TierCapacityMatrix.tsx
  • echo/frontend/src/components/workspace/UsageCard.tsx
  • echo/frontend/src/components/workspace/WorkspaceInviteWizard.tsx
  • echo/frontend/src/components/workspace/WorkspaceRequestHistory.tsx
  • echo/frontend/src/hooks/useWorkspace.ts
  • echo/frontend/src/hooks/useWorkspaceUsage.ts
  • echo/frontend/src/lib/tiers.ts
  • echo/frontend/src/lib/typesDirectus.d.ts
  • echo/frontend/src/routes/admin/AdminSettingsRoute.tsx
  • echo/frontend/src/routes/auth/Login.tsx
  • echo/frontend/src/routes/auth/Register.tsx
  • echo/frontend/src/routes/onboarding/OnboardingRoute.tsx
  • echo/frontend/src/routes/organisation/OrganisationRoute.tsx
  • echo/frontend/src/routes/project/CreateProjectRoute.tsx
  • echo/frontend/src/routes/project/conversation/ProjectConversationOverview.tsx
  • echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx
  • echo/frontend/src/routes/workspaces/CreateWorkspaceRoute.tsx
  • echo/frontend/src/routes/workspaces/WorkspaceSelectorRoute.tsx
  • echo/frontend/src/routes/workspaces/WorkspaceSettingsRoute.tsx
  • echo/scripts/create_schema.py
  • echo/scripts/matrix_smoke.py
  • echo/server/dembrane/api/chat.py
  • echo/server/dembrane/api/v2/__init__.py
  • echo/server/dembrane/api/v2/admin.py
  • echo/server/dembrane/api/v2/auth.py
  • echo/server/dembrane/api/v2/bff/conversations.py
  • echo/server/dembrane/api/v2/onboarding.py
  • echo/server/dembrane/api/v2/orgs.py
  • echo/server/dembrane/api/v2/schemas.py
  • echo/server/dembrane/api/v2/workspace_requests.py
  • echo/server/dembrane/api/v2/workspace_settings.py
  • echo/server/dembrane/api/v2/workspaces.py
  • echo/server/dembrane/async_helpers.py
  • echo/server/dembrane/email_throttle.py
  • echo/server/dembrane/notifications.py
  • echo/server/dembrane/policies.py
  • echo/server/dembrane/scheduler.py
  • echo/server/dembrane/seat_capacity.py
  • echo/server/dembrane/service/conversation.py
  • echo/server/dembrane/tasks.py
  • echo/server/dembrane/tier_capacity.py
  • echo/server/dembrane/tier_downgrade.py
  • echo/server/email_templates/notification_digest.html
  • echo/server/email_templates/notification_digest.txt
  • echo/server/email_templates/registration_existing_account.html
  • echo/server/email_templates/registration_existing_account.txt
  • echo/server/email_templates/tier_expired.html
  • echo/server/email_templates/tier_expired.txt
  • echo/server/email_templates/tier_expiring_soon.html
  • echo/server/email_templates/tier_expiring_soon.txt
  • echo/server/email_templates/workspace_request_approved.html
  • echo/server/email_templates/workspace_request_approved.txt
  • echo/server/email_templates/workspace_request_denied.html
  • echo/server/email_templates/workspace_request_denied.txt
  • echo/server/email_templates/workspace_request_submitted.html
  • echo/server/email_templates/workspace_request_submitted.txt
  • echo/server/tests/test_admin_workspace_requests.py
  • echo/server/tests/test_approve_deny_action.py
  • echo/server/tests/test_chat_link_gating.py
  • echo/server/tests/test_discount_fields.py
  • echo/server/tests/test_email_throttle.py
  • echo/server/tests/test_locked_gate.py
  • echo/server/tests/test_onboarding.py
  • echo/server/tests/test_request_notifications.py
  • echo/server/tests/test_seat_capacity.py
  • echo/server/tests/test_stamp_over_cap.py
  • echo/server/tests/test_tier_capacity.py
  • echo/server/tests/test_tier_expiry.py
  • echo/server/tests/test_tier_expiry_prewarning.py
  • echo/server/tests/test_tier_upgrade_kind.py
  • echo/server/tests/test_usage_gates_api.py
  • echo/server/tests/test_workspace_requests.py

Walkthrough

Adds “free” tier and replaces hard caps with usage gates. Introduces workspace_request schema/endpoints, admin approve/deny, unified seats, over-cap stamping/locked gating, onboarding free seed, notifications with email throttling, tier expiry/prewarning schedulers, extensive frontend gating/UI, Directus snapshots, scripts, and comprehensive tests/docs.

Changes

Free Tier + Requests + Usage Gates

Layer / File(s) Summary
Backend tier, gating, and workflows
echo/server/dembrane/{tier_capacity.py,api/*,tasks.py,seat_capacity.py,notifications.py,scheduler.py,email_throttle.py}
Adds free tier, usage gates, is_over_cap stamping, locked gating/redaction, chat link gating, workspace requests submit/history/admin decision, unified seats, onboarding free seed, notifications and email throttle, expiry/prewarning cron.
Schema and scripts
echo/directus/sync/**, echo/scripts/create_schema.py, echo/scripts/matrix_smoke.py
Directus snapshots for new collection/fields/relations; workspace tier defaults; schema creation steps 17–21; smoke updates.
Frontend gating and admin UI
echo/frontend/src/**
Locked overlays, upload gating, chat selection disables, upgrade modal/request flow, usage card/hooks, unified seat banners/rollups, admin upgrades panel overhaul, discount editor, request history and selectors.
Docs and test plans
echo/docs/**
ADR, PRD, plans, issues/spec slices for free tier, requests, gating, expiry, notifications, discounts, guest unification.
Tests
echo/server/tests/**
Extensive unit/integration tests across usage gates, chat gating, expiry/prewarning, requests approval/denial/notifications, discounts, onboarding, seat capacity, tier capacity, email throttle.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Dembrane/echo#405 — Also modifies chat select-all/add-context behavior; overlaps with this PR’s locked/402 gating.
  • Dembrane/echo#305 — Touches ConversationChunkAudioTranscript UI; related to this PR’s transcriptLocked overlay path.
  • Dembrane/echo#322 — Modifies task_finish_conversation_hook; related to this PR’s over-cap stamping on finish.

Suggested labels

Feature, improvement

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch free-tier-and-request-workspaces

@ussaama ussaama requested a review from spashii May 14, 2026 16:37
@spashii spashii merged commit d037759 into main May 15, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants