Conversation
…Integration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… schema Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two-phase device sync: imports active devices (matching by member email, serial number, or external ID) and removes disappeared devices from the connection. Follows the same pattern as GenericEmployeeSyncService. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Guard Phase 2 deletion when no devices were successfully processed (prevents false deletes)
- Handle P2002 unique constraint violation on device create with fallback to update
- Replace `include: { user: true }` with `select: { id: true }` on member lookup
- Wrap Phase 2 deleteMany in try/catch to prevent uncaught DB errors
- Add test verifying no deletions occur when all devices are skipped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… endpoints Add device sync endpoints to the SyncController: - GET device-sync-provider: read the configured device sync provider - POST device-sync-provider: set/clear the device sync provider with validation - GET available-providers?syncType=device: filter providers by device_sync capability - POST dynamic/:providerSlug/devices: run DSL-based device sync with schema validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validate body.deviceSyncDefinition through SyncDefinitionSchema (applying defaults) and store it on both PUT upsert and POST create endpoints. Repository upsertBySlug and create methods updated to accept and pass through the new field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new run-device-sync Trigger.dev task that calls the existing device sync API endpoint for a single org+connection. The daily integration-checks-schedule orchestrator now also finds orgs with deviceSyncProvider set and triggers device sync tasks for each. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
7 issues found across 20 files
Confidence score: 2/5
- There is high regression risk in
apps/api/src/integration-platform/services/generic-device-sync.service.ts: skipped devices are omitted fromsyncedIdentifiers, which can cause valid provider devices to be deleted in Phase 2, and existing-device updates do not refreshmemberIdownership changes. apps/app/src/app/(app)/[orgId]/people/devices/hooks/useDeviceSync.tscurrently updates local provider state even whenapiClient.postfails, creating a concrete user-facing inconsistency where failed saves appear successful.apps/api/src/trigger/integration-platform/run-device-sync.tsandapps/api/src/trigger/integration-platform/run-integration-checks-schedule.tscan misreport system health (expiring valid credentials on generic 401s and returningsuccess: trueon failed batch triggering), which makes operational failures harder to detect and recover from.- Pay close attention to
apps/api/src/integration-platform/services/generic-device-sync.service.ts,apps/app/src/app/(app)/[orgId]/people/devices/hooks/useDeviceSync.ts,apps/api/src/trigger/integration-platform/run-device-sync.ts,apps/api/src/trigger/integration-platform/run-integration-checks-schedule.ts, andapps/api/src/integration-platform/controllers/dynamic-integrations.controller.ts- data deletion risk, false-success UI/state, incorrect connection erroring, misleading run status, and unhandled validation exceptions should be addressed before merge.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/app/src/app/(app)/[orgId]/people/devices/hooks/useDeviceSync.ts">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/devices/hooks/useDeviceSync.ts:82">
P1: Check `apiClient.post` errors before updating local provider state; this currently treats failed saves as success.</violation>
</file>
<file name="apps/api/src/trigger/integration-platform/run-integration-checks-schedule.ts">
<violation number="1" location="apps/api/src/trigger/integration-platform/run-integration-checks-schedule.ts:219">
P2: `success` is always returned as `true` even when task batch triggering throws, so partial/failed runs are reported as successful.</violation>
</file>
<file name="apps/api/src/trigger/integration-platform/run-device-sync.ts">
<violation number="1" location="apps/api/src/trigger/integration-platform/run-device-sync.ts:52">
P1: Don’t mark connection credentials as expired on every 401; internal service-token auth failures also return 401 and will incorrectly flip valid connections to error.</violation>
</file>
<file name="apps/api/src/integration-platform/controllers/dynamic-integrations.controller.ts">
<violation number="1" location="apps/api/src/integration-platform/controllers/dynamic-integrations.controller.ts:70">
P2: Handle invalid `deviceSyncDefinition` with `safeParse` and return a 400 error instead of letting `parse` throw.</violation>
<violation number="2" location="apps/api/src/integration-platform/controllers/dynamic-integrations.controller.ts:183">
P2: Use `safeParse` for `deviceSyncDefinition` in create flow to avoid unhandled parse exceptions.</violation>
</file>
<file name="apps/api/src/integration-platform/services/generic-device-sync.service.ts">
<violation number="1" location="apps/api/src/integration-platform/services/generic-device-sync.service.ts:98">
P1: Devices skipped for missing member are excluded from `syncedIdentifiers`, which can cause Phase 2 to delete still-present provider devices.</violation>
<violation number="2" location="apps/api/src/integration-platform/services/generic-device-sync.service.ts:135">
P1: Existing-device updates never refresh `memberId`, so device ownership changes from the provider are not applied.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| }; | ||
| } | ||
| return { | ||
| success: true, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Not a regression — this is a pre-existing pattern. The schedule task returned success: true before this PR. Changing it here would be unrelated scope creep.
There was a problem hiding this comment.
Thanks for the feedback! I already have a similar learning that covers this, so I'm keeping the existing one.
|
|
||
| const rawDeviceSyncDefCreate = body.deviceSyncDefinition; | ||
| const validatedDeviceSyncDefCreate = rawDeviceSyncDefCreate | ||
| ? SyncDefinitionSchema.parse(rawDeviceSyncDefCreate) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Same as above — follows the existing syncDefinition pattern which also uses parse. Both should be migrated to safeParse together in a separate PR for consistency.
There was a problem hiding this comment.
Thanks for the feedback! I already have a similar learning that covers this, so I'm keeping the existing one.
|
|
||
| const rawDeviceSyncDef = body.deviceSyncDefinition; | ||
| const validatedDeviceSyncDef = rawDeviceSyncDef | ||
| ? SyncDefinitionSchema.parse(rawDeviceSyncDef) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Intentionally matches the existing syncDefinition validation pattern on the line above, which also uses parse. Changing only the device variant to safeParse would be inconsistent — both should be changed together in a separate cleanup.
There was a problem hiding this comment.
Thanks for the feedback! I've saved this as a new learning to improve future reviews.
- Check apiClient error before updating state in setSyncProvider - Remove incorrect 401 connection error-marking in trigger task - Track all active device identifiers before member lookup in Phase 2 - Include memberId in device update for ownership changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
device_syncas a newIntegrationCapabilityso any integration (platform or dynamic) can declare device import supportGenericDeviceSyncService— a two-phase sync service (import active devices, remove disappeared ones) mirroring the existing employee sync pattern?syncType=device), provider selection (device-sync-provider), and dynamic device sync trigger endpointsuseDeviceSynchook andDeviceSyncProviderSelectorcomponent to the Devices tab in PeopledeviceSyncProvidersetTest plan
GenericDeviceSyncServicehas 7 unit tests covering: create, update, skip (no member), inactive exclusion, remove stale, keep current, false-delete guarddevice_synccapability, select it, click "Sync now"🤖 Generated with Claude Code
Summary by cubic
Adds device import from integrations with a new
device_synccapability, a two‑phase sync (import + prune), provider selection, and scheduled runs. ValidatesdeviceSyncDefinitionon dynamic integrations and safely handles ownership changes, unique conflicts, and pruning.New Features
device_synccapability andSyncDeviceschema in@trycompai/integration-platform; dynamic integrations can storedeviceSyncDefinition.GET/POST /v1/integrations/sync/device-sync-provider,GET /available-providers?syncType=device, andPOST /dynamic/:provider/devices; OAuth refresh support; logs persisted to check runs.GenericDeviceSyncServiceimports active devices (member email match, serial/external ID), updatesmemberIdon ownership changes, guards prune when none processed, and falls back on P2002 conflicts.Device.sourceenum +integrationConnectionId+externalDeviceId;Organization.deviceSyncProvider;DynamicIntegration.deviceSyncDefinition; index onDevice.integrationConnectionId.run-device-synctask in@trigger.dev; daily orchestrator triggers device sync for orgs with a provider set; tasks triggered in batches.useDeviceSynchook andDeviceSyncProviderSelectoron People → Devices; better error handling when setting provider; “Sync now” button.GenericDeviceSyncService; schedule tests updated.Migration
device_syncand include adeviceSyncDefinition.SERVICE_TOKEN_TRIGGER,BASE_URL) for@trigger.dev.device_syncintegration, set the provider in Devices, then click “Sync now”.Written for commit a632419. Summary will update on new commits.