Skip to content

perf(platform): optimize RLS query initialization#533

Merged
larryro merged 5 commits into
mainfrom
perf/rls-query-optimization
Feb 23, 2026
Merged

perf(platform): optimize RLS query initialization#533
larryro merged 5 commits into
mainfrom
perf/rls-query-optimization

Conversation

@larryro

@larryro larryro commented Feb 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • RLS query optimization: Replace getAuthenticatedUser (2 cross-component DB queries per call) with getAuthUserIdentity (0 DB queries, uses cryptographically-validated JWT identity). Parallelizes organization and team ID fetching with Promise.all() across all RLS helpers (queryWithRLS, mutationWithRLS, zQueryWithRLS, zMutationWithRLS).
  • Streaming stability fix: Make isStreaming sticky across transient reconnection states using a ref-based tracker, preventing typewriter animation resets when the connection briefly drops to "pending" status.
  • File attachment metadata: Enrich internal file attachment markers with fileName, fileType, and fileSize metadata so the client can extract structured FileAttachment objects without additional server queries.

Test plan

  • Verify RLS-protected queries still enforce access control correctly (org/team scoping)
  • Confirm chat messages stream smoothly without animation resets during reconnection
  • Test file attachments display correctly in chat (documents, images, text files)
  • Run npx tsc --noEmit from services/platform/ for type safety
  • Run npm run lint --workspace=@tale/platform

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • File attachments now display enriched metadata (filename, file type, file size) in messages
    • Team-based access control added to authorization system
  • Bug Fixes

    • Improved persistence of streaming message state across network reconnections
    • Enhanced detection of transient network errors for better reconnection handling
  • Tests

    • Added comprehensive test coverage for error handling, file attachment extraction, and streaming state behavior

Replace authComponent.getAuthUser (2 cross-component DB queries) with
getAuthUserIdentity (JWT-based, 0 DB queries) for RLS context setup.

Parallelize getUserOrganizations and getUserTeamIds calls using
Promise.all so the two adapter.findMany component queries run
concurrently instead of sequentially.

Reduces RLS setup from 4 sequential component queries to 2 parallel
queries + 1 JWT read, fixing query timeout on listWebsites and similar
RLS-wrapped queries.
…erable

Convex reactive hooks can briefly see undefined properties during
WebSocket reconnection. Classify these TypeErrors as transient so the
error boundary retries instead of showing a crash screen.
…states

Prevent typewriter animation from resetting when message status briefly
drops back to "pending" during WebSocket reconnection. Track streaming
keys in a ref and only clear them on terminal statuses (success/failed).
…nt-side extraction

Embed fileName, fileType, and fileSize in the fileId italic markers written
by the agent chat so the client can reconstruct structured FileAttachment
objects without an extra server round-trip. Add extractFileAttachments()
parser and wire it into useMessageProcessing.
@greptile-apps

greptile-apps Bot commented Feb 23, 2026

Copy link
Copy Markdown

Greptile Summary

This PR implements three focused performance and stability improvements:

RLS Query Optimization: Replaces getAuthenticatedUser (which performs 2 cross-component DB queries via authComponent.getAuthUser) with getAuthUserIdentity (0 DB queries, uses cryptographically-validated JWT identity from ctx.auth.getUserIdentity()). Additionally parallelizes organization and team ID fetching with Promise.all() across all RLS helpers (queryWithRLS, mutationWithRLS, zQueryWithRLS, zMutationWithRLS). This reduces sequential database round trips during query initialization.

Streaming Stability Fix: Implements a ref-based sticky isStreaming tracker (streamingKeysRef) in use-message-processing.ts that prevents typewriter animation resets when WebSocket reconnection causes transient "pending" status. Once a message enters "streaming" state, it remains streaming until terminal status ("success" or "failed") is reached. The error boundary also now treats TypeError with "Cannot read properties of undefined" as transient during reconnection.

File Attachment Metadata: Enriches internal file attachment markers with fileName, fileType, and fileSize metadata so the client can extract structured FileAttachment objects without additional server queries. The new format: *(fileId: abc123 | fileName: photo.jpg | fileType: image/jpeg | fileSize: 54321)* replaces the legacy *(fileId: abc123)* format.

Confidence Score: 5/5

  • Safe to merge - well-tested performance optimizations with comprehensive test coverage and no breaking changes
  • The changes are well-structured performance optimizations with strong safety guarantees: JWT identity is cryptographically validated by Convex before function execution, the sticky streaming behavior has comprehensive test coverage for edge cases, and file attachment enrichment is backward-compatible with legacy markers. All RLS helpers consistently apply the same optimization pattern.
  • No files require special attention

Important Files Changed

Filename Overview
services/platform/convex/lib/rls/helpers/query_with_rls.ts Replaced getAuthenticatedUser with getAuthUserIdentity and parallelized org/team fetching with Promise.all() for performance
services/platform/convex/lib/rls/helpers/mutation_with_rls.ts Applied same RLS optimization as queries - JWT-based auth and parallel data fetching
services/platform/app/features/chat/hooks/use-message-processing.ts Added sticky isStreaming tracker using ref to prevent animation resets during reconnection, plus file attachment metadata extraction
services/platform/app/components/error-boundaries/boundaries/layout-error-boundary.tsx Added TypeError detection for undefined property access during reconnection to transient error handling
services/platform/convex/lib/agent_chat/start_agent_chat.ts Enriched file attachment markers with fileName, fileType, and fileSize metadata in all three attachment types

Sequence Diagram

sequenceDiagram
    participant Client
    participant RLS Helper
    participant JWT Identity
    participant DB Queries
    
    Client->>RLS Helper: Query/Mutation Request
    
    Note over RLS Helper: OLD: getAuthenticatedUser
    RLS Helper-->>DB Queries: authComponent.getAuthUser<br/>(2 cross-component queries)
    DB Queries-->>RLS Helper: User data
    RLS Helper-->>DB Queries: getUserOrganizations (sequential)
    DB Queries-->>RLS Helper: Orgs
    RLS Helper-->>DB Queries: getUserTeamIds (sequential)
    DB Queries-->>RLS Helper: Teams
    
    Note over RLS Helper: NEW: getAuthUserIdentity + Promise.all
    RLS Helper->>JWT Identity: ctx.auth.getUserIdentity()<br/>(0 DB queries)
    JWT Identity->>RLS Helper: User identity from JWT
    
    par Parallel Fetching
        RLS Helper->>DB Queries: getUserOrganizations
        DB Queries->>RLS Helper: Orgs
    and
        RLS Helper->>DB Queries: getUserTeamIds
        DB Queries->>RLS Helper: Teams
    end
    
    RLS Helper->>RLS Helper: Apply RLS rules
    RLS Helper->>Client: Response with enforced access control
Loading

Last reviewed commit: 961c299

@coderabbitai

coderabbitai Bot commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

This PR extends error boundary transient error detection, enhances chat message processing with attachment extraction and streaming state persistence, refactors RLS helpers to use identity-based authentication with team ID data, and updates attachment reference formatting in markdown. Changes span error handling, chat features, authorization layer, and agent message building, introducing new utility functions, regex patterns for enriched attachment blocks, and consistent parameter passing of user team IDs across RLS rule evaluation paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'perf(platform): optimize RLS query initialization' directly describes the main change: optimizing RLS queries by replacing getAuthenticatedUser with getAuthUserIdentity and parallelizing data fetches, which aligns with the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf/rls-query-optimization

Comment @coderabbitai help to get the list of available commands and usage tips.

@larryro larryro merged commit ab9fe81 into main Feb 23, 2026
18 checks passed
@larryro larryro deleted the perf/rls-query-optimization branch February 23, 2026 03:37
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