feat: device import from integrations#2802
Open
Marfuen wants to merge 13 commits into
Open
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>
Contributor
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.
- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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; integration checks still batch-triggered.useDeviceSynchook andDeviceSyncProviderSelectoron People → Devices; improved 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 d45f2da. Summary will update on new commits.