Skip to content

feat(tenancy): implement multi tenancy#3

Open
egeuysall wants to merge 6 commits into
masterfrom
feat/multi-tenancy
Open

feat(tenancy): implement multi tenancy#3
egeuysall wants to merge 6 commits into
masterfrom
feat/multi-tenancy

Conversation

@egeuysall
Copy link
Copy Markdown
Owner

This pull request introduces multi-tenancy support for Shipr, enabling organization-scoped data isolation and plan-based limits for chat and file features. The changes refactor the backend to enforce tenant boundaries, update rate limits and quotas based on organization plans, and add role-based access control. The .env.example and backend logic are updated to support configurable limits for free and organization plans.

Multi-tenancy and organization-scoped data isolation:

  • Refactored convex/chat.ts and convex/files.ts to enforce organization boundaries for chat threads, messages, and files, replacing user-centric ownership checks with organization-centric checks (requireOrganizationThread, requireOrganizationFile). All relevant queries and mutations now operate within the active organization context. [1] [2]
  • Added role-based access control checks (requireOrgPermission) for chat and file operations, ensuring only authorized users can perform actions based on their organization role. [1] [2]

Plan-based configurable limits and quotas:

  • Updated .env.example to define separate rate limits and quotas for free and organization plans, covering chat message/thread limits, file size/count limits, and image upload rate limits. [1] [2]
  • Refactored backend logic to dynamically apply these limits per organization plan, using helper functions like getChatHistoryLimitsForPlan and getFileStorageLimitsForPlan. [1] [2]

API and identifier changes:

  • Renamed chat and file API endpoints to organization-scoped versions (e.g., listOrganizationChatThreads, getOrganizationFiles), and updated data models to use orgId and createdByUserId instead of userId. [1] [2]

Documentation and guidance:

  • Updated README.md to describe the multi-tenant variant, including tenant boundaries, backend isolation, billing scope, and deployment guidance. Added references to /docs/multi-tenancy.md for further details.

Security and validation improvements:

  • Enhanced file upload validation to cross-check actual file size and MIME type from storage, and enforce organization-specific limits and rate controls. [1] [2]

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shipr Ready Ready Preview, Comment Feb 21, 2026 8:58pm

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13daec3b2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread convex/lib/auth.ts
orgId,
orgRole,
orgPermissions,
orgPlan: normalizeOrganizationBillingPlan(orgPlanClaim),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require org plan claim for Convex entitlement checks

requireOrganizationContext silently normalizes a missing plan claim to free, so any deployment where the Convex JWT template only includes org id/role/permissions will under-entitle paid organizations in Convex logic. That causes Organizations workspaces to be treated as free for limits in convex/files.ts and convex/chat.ts even when Clerk billing is configured, which is a production-facing quota regression; this should fail fast when the plan claim is absent (or resolve the plan from a trusted source) instead of defaulting silently.

Useful? React with 👍 / 👎.

const { isLoaded, orgId } = useAuth();
const hasOrganizationContext = isLoaded && Boolean(orgId);

useSyncUser(hasOrganizationContext);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep user sync active before org context is selected

Gating useSyncUser on hasOrganizationContext introduces a race in first-time onboarding: after selecting/creating an organization, onboarding mutations can run before the background user sync creates the Convex users document, which makes updateOnboardingStep/completeOnboarding fail with User not found. This is user-visible on slower networks and should be avoided by syncing as soon as auth is loaded (or by creating the user record inside onboarding mutations).

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant