createAuthMiddleware was calling SET LOCAL on the raw PrismaClient
outside of any transaction. In PostgreSQL, SET LOCAL without a
transaction acts as a session-level SET, which can leak RLS context
to subsequent requests sharing the same pooled connection, enabling
cross-tenant data access.
Wrapped the setCurrentUser call and downstream handler execution
inside a $transaction block so SET LOCAL is automatically reverted
when the transaction ends (on both success and failure).
Added comprehensive test suite for db-context module verifying:
- RLS context is set on the transaction client, not the raw client
- next() executes inside the transaction boundary
- Authentication errors prevent any transaction from starting
- Errors in downstream handlers propagate correctly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap SET LOCAL in transactions for proper connection pooling
- Make workspaceId optional in query DTOs (derived from guards)
- Replace Error throws with UnauthorizedException in activity controller
- Update workspace guard to remove RLS context setting
- Document that services should use withUserContext/withUserTransaction
- Create workspace listing page at /settings/workspaces
- List all user workspaces with role badges
- Create new workspace functionality
- Display member count per workspace
- Create workspace detail page at /settings/workspaces/[id]
- Workspace settings (name, ID, created date)
- Member management with role editing
- Invite member functionality
- Delete workspace (owner only)
- Add workspace components:
- WorkspaceCard: Display workspace info with role badge
- WorkspaceSettings: Edit workspace settings and delete
- MemberList: Display and manage workspace members
- InviteMember: Send invitations with role selection
- Add WorkspaceMemberWithUser type to shared package
- Follow existing app patterns for styling and structure
- Use mock data (ready for API integration)
Implements #9, #10
- Team model with workspace membership
- TeamMember model with role-based access (OWNER, ADMIN, MEMBER)
- Row-Level Security policies for tenant isolation on 19 tables
- Helper functions: current_user_id(), is_workspace_member(), is_workspace_admin()
- Developer utilities in src/lib/db-context.ts for easy RLS integration
- Comprehensive documentation in docs/design/multi-tenant-rls.md
Database migrations:
- 20260129220941_add_team_model: Adds Team and TeamMember tables
- 20260129221004_add_rls_policies: Enables RLS and creates policies
Security features:
- Complete database-level tenant isolation
- Automatic query filtering based on workspace membership
- Defense-in-depth security with application and database layers
- Performance-optimized with indexes on workspace_id