Skip to content

chore(repo): sync develop into main after v0.3.0 release#34

Merged
RISHII7 merged 3 commits into
mainfrom
develop
Jun 30, 2026
Merged

chore(repo): sync develop into main after v0.3.0 release#34
RISHII7 merged 3 commits into
mainfrom
develop

Conversation

@RISHII7

@RISHII7 RISHII7 commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Bring the post-release sync merge commit onto main so main and develop are at the same commit level. No code changes — this is a pure history alignment commit.

Summary by CodeRabbit

  • New Features

    • Added organization selection for signed-in users and a clearer sign-in/sign-up experience.
    • Introduced dashboard access checks so users are guided through sign-in and organization setup before entering protected areas.
  • Bug Fixes

    • Redirected authenticated users without an organization to the organization selection flow automatically.
    • Updated the app entry flow so dashboard content is shown in the intended route structure.
  • Documentation

    • Refreshed the README and changelog to reflect the new organization-focused app structure and release notes.

RISHII7 added 3 commits June 30, 2026 13:01
Introduces multi-tenant organization support via Clerk Organizations and
refactors the entire authentication layer into a dedicated feature module
under apps/web/modules/auth/, separating routing from domain logic.

## Auth module architecture

Extracted all auth UI into modules/auth/ui/ following a views/layouts/components
structure:

- AuthLayout      — full-screen centered wrapper for all auth pages
- SignInView       — <SignIn routing=hash /> (hash routing prevents full-page
                     navigations on Clerk multi-step flows)
- SignUpView       — <SignUp routing=hash />
- OrgSelectionView — <OrganizationList hidePersonal skipInvitationScreen> with
                     post-selection redirect to /
- AuthGuard        — Convex Authenticated/Unauthenticated/AuthLoading guard;
                     shows SignInView inline when unauthenticated (no redirect)
- OrganizationGuard — useOrganization() guard; renders OrgSelectionView inside
                      AuthLayout when no active org is present

## Guard composition at dashboard layout level

app/(dashboard)/layout.tsx wraps all dashboard routes with:

  <AuthGuard>
    <OrganizationGuard>
      {children}
    </OrganizationGuard>
  </AuthGuard>

Both conditions (Convex session + Clerk org) must be satisfied before any
dashboard page renders. No per-page checks required.

## Organization redirect in middleware

proxy.ts extended with org enforcement:
- isOrgFreeRoute matcher covers /sign-in, /sign-up, /org-selection
- Authenticated users without an active orgId are redirected to
  /org-selection?redirectUrl=<original> unless already on an org-free route

## Auth pages refactored to module views

- app/(auth)/layout.tsx        → delegates to <AuthLayout>
- app/(auth)/sign-in/page.tsx  → delegates to <SignInView>
- app/(auth)/sign-up/page.tsx  → delegates to <SignUpView>
- app/(auth)/org-selection/page.tsx (new) → delegates to <OrgSelectionView>

## Dashboard page

app/(dashboard)/page.tsx replaces the deleted app/page.tsx as the application
root. Shows UserButton, OrganizationSwitcher (hidePersonal), and the Convex
users table demo (useQuery + useMutation).

## Docs

- CHANGELOG.md updated with v0.4.0 section; compare link added
- README.md: Organizations added to Features; Architecture and Project
  Structure sections updated to reflect modules/ and route groups
#35)

feat(web): add Clerk organizations with module-based auth architecture
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces Clerk Organizations support via a new module-based auth architecture under apps/web/modules/auth, including AuthLayout, AuthGuard, OrganizationGuard, and view components for sign-in, sign-up, and org-selection. Auth route pages and a new dashboard layout/page are wired to these components, proxy.ts middleware now redirects authenticated users without an organization to /org-selection, the root page is removed, and README/CHANGELOG are updated accordingly.

Changes

Organizations and module-based auth

Layer / File(s) Summary
Auth UI module: layout, guards, views
apps/web/modules/auth/ui/layouts/auth-layout/index.tsx, apps/web/modules/auth/ui/components/auth-guard/index.tsx, apps/web/modules/auth/ui/components/organization-guard/index.tsx, apps/web/modules/auth/ui/views/sign-in-view/index.tsx, apps/web/modules/auth/ui/views/sign-up-view/index.tsx, apps/web/modules/auth/ui/views/org-selection-view/index.tsx
Adds a centered AuthLayout, an AuthGuard that renders loading/sign-in/children based on auth state, an OrganizationGuard that renders org-selection or children based on organization presence, and Clerk-backed sign-in, sign-up, and org-selection view components.
Route pages wired to new views
apps/web/app/(auth)/layout.tsx, apps/web/app/(auth)/sign-in/[[...sign-in]]/page.tsx, apps/web/app/(auth)/sign-up/[[...sign-up]]/page.tsx, apps/web/app/(auth)/org-selection/[[...org-selection]]/page.tsx
Auth layout now wraps children with AuthLayout; sign-in/sign-up pages render the new SignInView/SignUpView instead of Clerk components directly; adds a new org-selection page rendering OrgSelectionView.
Dashboard guard composition and page
apps/web/app/(dashboard)/layout.tsx, apps/web/app/(dashboard)/page.tsx, apps/web/app/page.tsx
Adds a dashboard layout nesting AuthGuard and OrganizationGuard, adds a new dashboard page using Convex queries/mutations with UserButton/OrganizationSwitcher, and removes the old root page implementation.
Middleware org redirect logic
apps/web/proxy.ts
Adds an isOrgFreeRoute matcher and redirects authenticated users without an orgId to /org-selection, preserving the original URL via redirectUrl.
Documentation updates
CHANGELOG.md, README.md
Documents v0.4.0 release notes and updates compare links; updates feature list, architecture tree, and project structure to reflect the new auth module and route groups.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProxyMiddleware
  participant AuthGuard
  participant OrganizationGuard
  participant ClerkAPI

  User->>ProxyMiddleware: request protected route
  ProxyMiddleware->>ClerkAPI: auth.protect()
  alt no orgId and not org-free route
    ProxyMiddleware-->>User: redirect to /org-selection
  else has orgId or org-free route
    ProxyMiddleware->>AuthGuard: pass through to page
    AuthGuard->>ClerkAPI: check auth state
    alt unauthenticated
      AuthGuard-->>User: render SignInView
    else authenticated
      AuthGuard->>OrganizationGuard: render children
      OrganizationGuard->>ClerkAPI: useOrganization()
      alt no organization
        OrganizationGuard-->>User: render OrgSelectionView
      else has organization
        OrganizationGuard-->>User: render dashboard children
      end
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • RISHII7/echo#2: Both PRs touch apps/web/app/(auth)/layout.tsx and the sign-in/sign-up pages, changing how Clerk auth components are rendered.
  • RISHII7/echo#4: Both PRs implement the same module-based AuthLayout/AuthGuard/OrganizationGuard refactor and the middleware redirect to /org-selection when an orgId is missing.
  • RISHII7/echo#31: Both PRs modify apps/web/proxy.ts middleware controlling public route matching and auth enforcement.

Poem

Hop, hop, through the org-selection door,
AuthGuard watches, evermore.
No more lone page rendering bare,
Now modules, guards, and views to share.
A redirect here, a layout there—
This rabbit's burrow's now fully square! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title correctly describes the merge/sync nature of the PR, though it omits the substantial Clerk auth and documentation updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


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.

@RISHII7
RISHII7 merged commit 0468d69 into main Jun 30, 2026
20 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/proxy.ts (1)

4-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared auth-free route list.

The sign-in/sign-up patterns now live in two separate matchers. The next route change only needs one missed update to create a redirect bug, so it is safer to define the shared list once and extend it for org-free routes.

♻️ Proposed refactor
-const isPublicRoute = createRouteMatcher(["/sign-in(.*)", "/sign-up(.*)"])
-
-const isOrgFreeRoute = createRouteMatcher([
-  "/sign-in(.*)",
-  "/sign-up(.*)",
-  "/org-selection(.*)",
-])
+const publicRoutes = ["/sign-in(.*)", "/sign-up(.*)"]
+
+const isPublicRoute = createRouteMatcher(publicRoutes)
+const isOrgFreeRoute = createRouteMatcher([
+  ...publicRoutes,
+  "/org-selection(.*)",
+])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/proxy.ts` around lines 4 - 10, The auth-free route patterns are
duplicated between isPublicRoute and isOrgFreeRoute, which makes future route
changes easy to miss; extract the shared sign-in/sign-up matcher list into a
single constant in proxy.ts and reuse it when defining both createRouteMatcher
calls, adding the org-selection pattern only for the org-free matcher.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/app/`(dashboard)/page.tsx:
- Line 18: The Add button currently triggers addUser() without any in-flight
protection, so repeated clicks can submit duplicate api.users.add mutations.
Update the page component’s button handling in the dashboard page so the button
is disabled while the add mutation is pending, and make addUser() short-circuit
or otherwise respect that pending state. Use the existing addUser handler and
the Button component to gate clicks until the mutation settles.

In `@CHANGELOG.md`:
- Line 14: The changelog version heading does not match the PR’s stated
post-release sync target, so update the release section in CHANGELOG.md to use
the intended version consistently. Verify whether this change should be recorded
under v0.3.0 or v0.4.0, then align the top-level changelog entry and any related
release metadata with that same version to avoid release/tagging confusion.

---

Nitpick comments:
In `@apps/web/proxy.ts`:
- Around line 4-10: The auth-free route patterns are duplicated between
isPublicRoute and isOrgFreeRoute, which makes future route changes easy to miss;
extract the shared sign-in/sign-up matcher list into a single constant in
proxy.ts and reuse it when defining both createRouteMatcher calls, adding the
org-selection pattern only for the org-free matcher.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71f43498-e149-4484-afa8-c3693f78cdc8

📥 Commits

Reviewing files that changed from the base of the PR and between 7335e42 and 5f82779.

📒 Files selected for processing (16)
  • CHANGELOG.md
  • README.md
  • apps/web/app/(auth)/layout.tsx
  • apps/web/app/(auth)/org-selection/[[...org-selection]]/page.tsx
  • apps/web/app/(auth)/sign-in/[[...sign-in]]/page.tsx
  • apps/web/app/(auth)/sign-up/[[...sign-up]]/page.tsx
  • apps/web/app/(dashboard)/layout.tsx
  • apps/web/app/(dashboard)/page.tsx
  • apps/web/app/page.tsx
  • apps/web/modules/auth/ui/components/auth-guard/index.tsx
  • apps/web/modules/auth/ui/components/organization-guard/index.tsx
  • apps/web/modules/auth/ui/layouts/auth-layout/index.tsx
  • apps/web/modules/auth/ui/views/org-selection-view/index.tsx
  • apps/web/modules/auth/ui/views/sign-in-view/index.tsx
  • apps/web/modules/auth/ui/views/sign-up-view/index.tsx
  • apps/web/proxy.ts
💤 Files with no reviewable changes (1)
  • apps/web/app/page.tsx

<p> apps/web</p>
<UserButton />
<OrganizationSwitcher hidePersonal />
<Button onClick={() => addUser()}>Add</Button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Gate the add mutation behind an in-flight state.

Line 18 fires api.users.add on every click and never disables the button, so double-clicks can enqueue multiple writes before the first mutation settles. That is risky on an add path.

♻️ Proposed fix
+import { useState } from "react"
 import { useMutation, useQuery } from "convex/react"
 import { OrganizationSwitcher, UserButton } from "`@clerk/nextjs`"
@@
 export default function Page() {
   const users = useQuery(api.users.getMany)
   const addUser = useMutation(api.users.add)
+  const [isAdding, setIsAdding] = useState(false)
+
+  const handleAddUser = async () => {
+    if (isAdding) return
+    setIsAdding(true)
+    try {
+      await addUser()
+    } finally {
+      setIsAdding(false)
+    }
+  }
+
   return (
@@
-      <Button onClick={() => addUser()}>Add</Button>
+      <Button disabled={isAdding} onClick={handleAddUser}>
+        Add
+      </Button>
📝 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
<Button onClick={() => addUser()}>Add</Button>
<Button disabled={isAdding} onClick={handleAddUser}>
Add
</Button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/app/`(dashboard)/page.tsx at line 18, The Add button currently
triggers addUser() without any in-flight protection, so repeated clicks can
submit duplicate api.users.add mutations. Update the page component’s button
handling in the dashboard page so the button is disabled while the add mutation
is pending, and make addUser() short-circuit or otherwise respect that pending
state. Use the existing addUser handler and the Button component to gate clicks
until the mutation settles.

Comment thread CHANGELOG.md

---

## [0.4.0] - 2026-07-01

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major

Version mismatch between PR objectives and changelog.

The PR objectives describe this as a post-release synchronization for v0.3.0, but the changelog introduces a v0.4.0 release section. Please confirm the intended version — this discrepancy could cause confusion in release automation and tagging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 14, The changelog version heading does not match the
PR’s stated post-release sync target, so update the release section in
CHANGELOG.md to use the intended version consistently. Verify whether this
change should be recorded under v0.3.0 or v0.4.0, then align the top-level
changelog entry and any related release metadata with that same version to avoid
release/tagging confusion.

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