Skip to content

eng-256: System Bootstrap#356

Merged
Connorbelez merged 4 commits intomainfrom
Connorbelez/eng-256-system-bootstrap
Mar 30, 2026
Merged

eng-256: System Bootstrap#356
Connorbelez merged 4 commits intomainfrom
Connorbelez/eng-256-system-bootstrap

Conversation

@Connorbelez
Copy link
Copy Markdown
Owner

@Connorbelez Connorbelez commented Mar 30, 2026

ENG-255

  • CRM system-object adapter work and records-query integration.

ENG-256

  • CRM system bootstrap for organization setup and admin bootstrap flows.

Summary by CodeRabbit

  • New Features
    • Automatic setup of core CRM objects (Mortgage, Borrower, Lender, Broker, Deal, Obligation) when organizations are created
    • Cursor-based pagination for improved performance when querying large datasets

@linear
Copy link
Copy Markdown

linear bot commented Mar 30, 2026

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d566a000-3799-471f-92ab-feb9fbaf5785

📥 Commits

Reviewing files that changed from the base of the PR and between 2141fed and 7d3f5a2.

📒 Files selected for processing (11)
  • convex/auth.ts
  • convex/crm/recordQueries.ts
  • convex/crm/systemAdapters/bootstrap.ts
  • convex/crm/systemAdapters/queryAdapter.ts
  • specs/ENG-255/tasks.md
  • specs/ENG-256/chunks/chunk-01-bootstrap-core/context.md
  • specs/ENG-256/chunks/chunk-01-bootstrap-core/tasks.md
  • specs/ENG-256/chunks/chunk-02-webhook-integration/context.md
  • specs/ENG-256/chunks/chunk-02-webhook-integration/tasks.md
  • specs/ENG-256/chunks/manifest.md
  • specs/ENG-256/tasks.md

📝 Walkthrough

Walkthrough

This PR implements system object bootstrapping for CRM entities (mortgage, borrower, lender, broker, deal, obligation) by introducing metadata and idempotent creation logic, integrating organization-creation webhooks to trigger automatic setup, and enhancing record querying to support native table pagination and system object retrieval.

Changes

Cohort / File(s) Summary
System Object Bootstrap
convex/crm/systemAdapters/bootstrap.ts
New module defining SystemObjectConfig interface and SYSTEM_OBJECT_CONFIGS constant covering six CRM entities with field mappings and select options. Implements bootstrapForOrg shared logic for idempotent object/field/view creation, plus bootstrapSystemObjects (internal mutation) and adminBootstrap (public mutation) entry points with audit logging.
Webhook Integration
convex/auth.ts
Schedules internal.crm.systemAdapters.bootstrap.bootstrapSystemObjects via ctx.scheduler.runAfter(0, { orgId }) asynchronously after upsertOrganization in the organization.created handler.
Query Layer Pagination
convex/crm/systemAdapters/queryAdapter.ts
Added cursor-based pagination support via new paginateNativeTable helper and function overloads for queryNativeTable and queryNativeRecords, returning NativeTablePage and NativeRecordPage objects with page, continueCursor, and isDone fields. Introduced exported NativeTableName type.
System Object Query Handling
convex/crm/recordQueries.ts
Refactored system object querying: introduced collectNativeRecordsForFiltering helper for batched native record collection; updated queryRecords to use native table queries directly for unfiltered/unsorted pagination with cursor support, and to use native collection for filtered/sorted paths instead of EAV-only logic.
Documentation & Specs
specs/ENG-256/*, specs/ENG-255/tasks.md
Added implementation specification chunks for bootstrap core and webhook integration, including context docs and task checklists. Updated ENG-255 reference from specific issue to follow-up. Added master task document at specs/ENG-256/tasks.md summarizing two completed work chunks.

Sequence Diagram

sequenceDiagram
    participant WorkOS as WorkOS API
    participant Handler as auth.ts<br/>(organization.created)
    participant Scheduler as Convex Scheduler
    participant Bootstrap as bootstrap.ts<br/>(bootstrapSystemObjects)
    participant DB as Convex Database

    WorkOS->>Handler: organization.created event<br/>(event.data.id)
    Handler->>DB: upsertOrganization(event.data)
    DB-->>Handler: organization updated/created
    Handler->>Scheduler: ctx.scheduler.runAfter(0,<br/>bootstrapSystemObjects,<br/>{orgId: event.data.id})
    Scheduler-->>Handler: scheduled (returns)
    Handler-->>WorkOS: webhook complete
    
    Note over Scheduler,Bootstrap: Async execution in<br/>separate transaction
    Scheduler->>Bootstrap: invoke(ctx, {orgId})
    Bootstrap->>DB: query existing objectDefs<br/>for orgId
    DB-->>Bootstrap: [existing objects]
    
    loop For each SYSTEM_OBJECT_CONFIGS
        Bootstrap->>DB: insert objectDefs<br/>(if not exists)
        DB-->>Bootstrap: objectDef created
        Bootstrap->>DB: insert viewDefs<br/>(default view)
        DB-->>Bootstrap: viewDef created
        
        loop For each field in object
            Bootstrap->>DB: insert fieldDefs<br/>(nativeReadOnly: true)
            Bootstrap->>DB: derive & insert<br/>fieldCapabilities
            Bootstrap->>DB: insert viewFields
        end
    end
    
    Bootstrap-->>Scheduler: return {created, skipped}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

  • eng-251 #351: Extends convex/crm/recordQueries.ts with native-backed pagination and system-object handling, building on the same query logic patterns introduced here.
  • eng-255 #353: Modifies CRM system-adapter and native-query code paths (recordQueries.ts, queryAdapter.ts), sharing significant overlap with the query infrastructure changes in this PR.

Poem

🐰✨ A hop and a skip, the objects now grow,
Native tables bloom where system seeds sow,
Bootstrap the mortgages, lenders, and deals,
With cursor-led queries on pagination wheels! 🎡
From webhook to scheduler, async we fly—
Six CRM entities reaching the sky! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'eng-256: System Bootstrap' directly corresponds to the main objective of the PR: implementing system object bootstrapping for ENG-256, including bootstrap core infrastructure and webhook integration.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ 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 Connorbelez/eng-256-system-bootstrap

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 and usage tips.

Copy link
Copy Markdown
Owner Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@Connorbelez Connorbelez changed the title eng-255 eng-256: System Bootstrap Mar 30, 2026
@Connorbelez Connorbelez marked this pull request as ready for review March 30, 2026 15:01
Copilot AI review requested due to automatic review settings March 30, 2026 15:01
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the initial “system objects” foundation for CRM by adding native-table adapters (ENG-255) and introducing automated bootstrapping of system objectDefs/fieldDefs for new organizations (ENG-256), including a webhook trigger on org creation.

Changes:

  • Added system adapter utilities (columnResolver, queryAdapter) and wired queryRecords to query native tables for system objects.
  • Added system object bootstrap mutation(s) to create system objectDefs/fieldDefs/views + scheduled bootstrap from organization.created webhook.
  • Added ENG-255/ENG-256 spec/chunk planning docs.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
convex/crm/systemAdapters/columnResolver.ts Resolves native column paths (including nested paths) with basic coercion for date/datetime fields.
convex/crm/systemAdapters/queryAdapter.ts Adds switch-based routing to query 6 native tables and assemble UnifiedRecord[] for system objects.
convex/crm/recordQueries.ts Routes system-object queryRecords through the native adapter; updates system-object behavior in getRecord/searchRecords.
convex/crm/systemAdapters/bootstrap.ts Adds idempotent system object bootstrapping (internal + admin entrypoint) creating objectDefs/fieldDefs/capabilities/views.
convex/auth.ts Schedules system bootstrap after WorkOS organization.created upsert.
specs/ENG-256/** ENG-256 task lists + chunk context/manifest docs.
specs/ENG-255/** ENG-255 task lists + chunk context/manifest docs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread convex/crm/recordQueries.ts Outdated
Comment thread convex/crm/systemAdapters/queryAdapter.ts Outdated
Comment thread convex/crm/systemAdapters/bootstrap.ts Outdated
Comment thread convex/crm/systemAdapters/bootstrap.ts Outdated
Comment thread convex/crm/systemAdapters/bootstrap.ts
Comment thread specs/ENG-256/chunks/manifest.md
Comment thread specs/ENG-255/chunks/manifest.md
Comment thread specs/ENG-256/tasks.md
Copy link
Copy Markdown
Owner Author

@coderabbitai please review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

@Connorbelez Sure! I'll kick off a review of PR #356 right away.


🧠 Learnings used
Learnt from: Connorbelez
Repo: Connorbelez/tanstackTemplate PR: 5
File: specs/governed-transitions/chunks/chunk-01-schema-machine/context.md:209-213
Timestamp: 2026-03-13T03:17:28.559Z
Learning: In the Connorbelez/tanstackTemplate repository, do not flag .md files for markdown formatting/linting issues (e.g., MD040 fenced code block language). Only reference .md files (specs, PRDs, design docs) when they reveal architectural drift or implementation inconsistencies against actual code.

Learnt from: CR
Repo: Connorbelez/tanstackTemplate PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T18:28:26.698Z
Learning: After completing a major unit of work, run `coderabbit review --plain` to get a code review summary and check for potential issues or improvements

Learnt from: CR
Repo: Connorbelez/tanstackTemplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-16T06:17:10.192Z
Learning: After completing a major unit of work, run `coderabbit review --plain` to get a code review summary and check for potential issues or improvements

Learnt from: CR
Repo: Connorbelez/tanstackTemplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-16T16:49:07.666Z
Learning: After completing a major unit of work, run `coderabbit review --plain` to get a code review summary and check for potential issues or improvements

Learnt from: CR
Repo: Connorbelez/tanstackTemplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-16T15:27:40.455Z
Learning: Use React, TanStack Router, TanStack Query with Convex query integration, Tailwind CSS, and ShadCN UI for frontend development
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (2)
convex/crm/recordQueries.ts (1)

590-593: Prefer explicit unsupported signaling over unconditional empty results.

Always returning [] for system-object search makes the UI look like “no matches” instead of “not supported yet.” Consider throwing a specific ConvexError (or adding a bounded fallback) so behavior is explicit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@convex/crm/recordQueries.ts` around lines 590 - 593, The current branch that
handles native/system-object search returns an unconditional empty array which
makes the UI show “no matches”; instead modify the branch in the search handler
(e.g., the function handling system-object search in
recordQueries.ts—searchRecords or the native-table search branch) to explicitly
signal unsupported behavior: throw a ConvexError with a clear message like
"system-object search not supported yet" (or return a bounded fallback result
plus a flag), and ensure the calling code/UI can detect and surface this
unsupported state rather than treating it as an empty result set.
convex/crm/systemAdapters/queryAdapter.ts (1)

77-116: updatedAt always uses _creationTime — verify this is intentional.

The updatedAt field is set to doc._creationTime (line 113) rather than attempting to use a native updatedAt field. This means records will show their creation time as the update time.

Per the spec in context.md, this appears intentional since native tables don't have a consistent updatedAt field. However, if any native tables do track updates (e.g., lastTransitionAt on some tables), you may want to use that instead for a more accurate timestamp.

💡 Optional: Consider using `lastTransitionAt` where available
 return {
   _id: String(doc._id),
   _kind: "native" as const,
   objectDefId: objectDef._id,
   fields,
   createdAt:
     (doc.createdAt as number) ?? (doc._creationTime as number),
-  updatedAt: doc._creationTime as number,
+  updatedAt:
+    (doc.lastTransitionAt as number) ??
+    (doc.createdAt as number) ??
+    (doc._creationTime as number),
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@convex/crm/systemAdapters/queryAdapter.ts` around lines 77 - 116, The
updatedAt is currently always set from doc._creationTime in queryNativeRecords;
change it to prefer a native updated timestamp when available (e.g., check
doc.updatedAt or doc.lastTransitionAt) and fall back to doc._creationTime if
none exists. Update the mapping in queryNativeRecords (and the returned object’s
updatedAt) to first look for doc.updatedAt, then doc.lastTransitionAt, then
doc._creationTime; keep createdAt logic unchanged (createdAt: (doc.createdAt as
number) ?? (doc._creationTime as number)). Ensure types/casts match existing
pattern and only adjust the return construction where updatedAt is assigned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@convex/crm/recordQueries.ts`:
- Around line 335-349: The native-system branch (where objectDef.isSystem &&
objectDef.nativeTable) ignores args.paginationOpts.cursor and always returns
continueCursor: null/isDone: true/truncated: false; update this path to accept
and honor args.paginationOpts.cursor and args.paginationOpts.numItems when
calling queryNativeRecords (or extend queryNativeRecords to accept a
cursor/offset), and compute/return the correct pagination metadata
(continueCursor when more rows remain, isDone only when no more records,
truncated if the returned page was cut by numItems) instead of always signalling
completion; keep references to objectDef.isSystem, objectDef.nativeTable,
queryNativeRecords, args.paginationOpts.cursor, args.paginationOpts.numItems and
the continueCursor/isDone/truncated fields so you modify the exact branch and
return shape.
- Around line 471-474: The error message thrown in the unsupported path inside
the getRecord logic (the throw new ConvexError(...) that mentions ENG-256) is
stale; update the string to remove or replace the ENG-256 reference with the
correct follow-up ticket or a generic "future enhancement" note (e.g., "deferred
to follow-up ticket" or "future enhancement") so the ConvexError thrown by
getRecord/system-object handling no longer references ENG-256.

---

Nitpick comments:
In `@convex/crm/recordQueries.ts`:
- Around line 590-593: The current branch that handles native/system-object
search returns an unconditional empty array which makes the UI show “no
matches”; instead modify the branch in the search handler (e.g., the function
handling system-object search in recordQueries.ts—searchRecords or the
native-table search branch) to explicitly signal unsupported behavior: throw a
ConvexError with a clear message like "system-object search not supported yet"
(or return a bounded fallback result plus a flag), and ensure the calling
code/UI can detect and surface this unsupported state rather than treating it as
an empty result set.

In `@convex/crm/systemAdapters/queryAdapter.ts`:
- Around line 77-116: The updatedAt is currently always set from
doc._creationTime in queryNativeRecords; change it to prefer a native updated
timestamp when available (e.g., check doc.updatedAt or doc.lastTransitionAt) and
fall back to doc._creationTime if none exists. Update the mapping in
queryNativeRecords (and the returned object’s updatedAt) to first look for
doc.updatedAt, then doc.lastTransitionAt, then doc._creationTime; keep createdAt
logic unchanged (createdAt: (doc.createdAt as number) ?? (doc._creationTime as
number)). Ensure types/casts match existing pattern and only adjust the return
construction where updatedAt is assigned.
🪄 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: a352cb35-32cf-4a10-ad99-fc3ec6d8e63d

📥 Commits

Reviewing files that changed from the base of the PR and between f19570b and 2141fed.

📒 Files selected for processing (17)
  • convex/auth.ts
  • convex/crm/recordQueries.ts
  • convex/crm/systemAdapters/bootstrap.ts
  • convex/crm/systemAdapters/columnResolver.ts
  • convex/crm/systemAdapters/queryAdapter.ts
  • specs/ENG-255/chunks/chunk-01-adapter-infrastructure/context.md
  • specs/ENG-255/chunks/chunk-01-adapter-infrastructure/tasks.md
  • specs/ENG-255/chunks/chunk-02-integration/context.md
  • specs/ENG-255/chunks/chunk-02-integration/tasks.md
  • specs/ENG-255/chunks/manifest.md
  • specs/ENG-255/tasks.md
  • specs/ENG-256/chunks/chunk-01-bootstrap-core/context.md
  • specs/ENG-256/chunks/chunk-01-bootstrap-core/tasks.md
  • specs/ENG-256/chunks/chunk-02-webhook-integration/context.md
  • specs/ENG-256/chunks/chunk-02-webhook-integration/tasks.md
  • specs/ENG-256/chunks/manifest.md
  • specs/ENG-256/tasks.md

Comment thread convex/crm/recordQueries.ts Outdated
Comment thread convex/crm/recordQueries.ts Outdated
@Connorbelez Connorbelez force-pushed the Connorbelez/eng-256-system-bootstrap branch from 2141fed to 7d3f5a2 Compare March 30, 2026 17:43
@Connorbelez Connorbelez merged commit 076269f into main Mar 30, 2026
0 of 3 checks passed
This was referenced Mar 30, 2026
@coderabbitai coderabbitai bot mentioned this pull request Apr 13, 2026
Connorbelez added a commit that referenced this pull request Apr 20, 2026
ENG-255
- CRM system-object adapter work and records-query integration.

ENG-256
- CRM system bootstrap for organization setup and admin bootstrap flows.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * System objects (Mortgage, Borrower, Lender, Broker, Deal, Obligation) can now be queried through the standard records interface
  * System objects are automatically set up when organizations are created
  * Added admin capability to manually bootstrap system objects

* **Bug Fixes**
  * System object queries no longer return \"not yet implemented\" errors

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

2 participants