Objective
- Ensure one online Attik booking produces exactly one Spectora order, with that Spectora job id stored on the Attik inspection (
_spectoraJobId). - Prevent orphan Spectora orders (API-created jobs in Spectora that no Attik work order references), which break cancel/resync workflows and confuse coordinators.
Background
- Reported on work order 1008592205: a single Attik order exists, but two Spectora orders were created; both show creator "Attik API" in Spectora, and only one is linked on the Attik side.
- The affected job was booked through the public online scheduler (customer flow), not the internal scheduler’s Attik-vs-Spectora picker.
- For companies on Attik standalone (or
beta-online-scheduler-attik), the online UI callsinspection/book-jobonly—it does not callspectora/create-jobon the same booking. Spectora jobs for those bookings are created by barebones sync after the Attik inspection is saved. - In Spectora, "Attik API" is consistent with jobs created via the API key integration (barebones
POST inspectionsand fullcreateSpectoraJobboth use that path). Online Attik bookings that sync to Spectora use barebones sync withscheduled_by: attik-standaloneon the Spectora payload. - Suspected failure mode: two overlapping barebones "create" runs both execute before
_spectoraJobIdis persisted—e.g. async sync on inspection insert while a follow-up inspection update (or a second sync trigger) still sees no linked id.createInspectionperforms a second save to attach events immediately after the first save; the change stream also fires barebones sync on later updates when status, charges, datetime, inspectors, or address change. - Slack thread: attik-talk discussion.
Scope
Frontend (online scheduler)
- Public booking is implemented in
attik-frontend/src/app/scheduler/summary/BookingJobLoader.tsx: whencompany.attikStandaloneorbeta-online-scheduler-attikis enabled, it posts toinspection/book-jobwithscheduledLocation: 'online'(notspectora/create-job). hasBookedRefguards against double-submit in the loader; if duplicate Spectora jobs appear, investigation should include server-side duplicate creates, not only UI double-click.
Backend (booking)
POST /inspection/book-jobinattik-backend/src/routes/inspection.tscallscreateInspectioninsrc/util/functions/inspection/createInspection.ts, which setsjobCreationType: 'attik'andscheduledLocation: 'online'(default when not internal).- Confirmed vs unconfirmed on create follows company schedule settings (
createBookedJobsAsConfirmed); that affects whether later confirm updates also qualify for barebones sync.
Backend (Spectora link)
- After insert (and on qualifying updates),
attik-backend/src/events/streamHandlers/inspectionStream.tsinvokessyncBarebonesSpectoraJobfromsrc/util/functions/spectora/syncBarebonesSpectoraJob.tsforjobCreationType === 'attik'. - Barebones sync creates via Spectora
POST inspectionswhen_spectoraJobIdis missing, then updates when present. There is a late re-read for_spectoraJobIdbefore create, but no distributed lock—concurrent runs can still double-create; only one id is typically saved on Attik. - Spectora webhooks in
src/routes/webhooks/spectora/syncInspection.tsskip upsert whenscheduled_by === 'attik-standalone'or when an Attik inspection already owns the Spectora job id—so the duplicate is unlikely to be webhook-created Attik rows; focus on duplicate API creates. - Full Spectora-first booking (
src/routes/spectora.ts→createSpectoraJob) is out of scope for this repro unless investigation shows the company was not on standalone at book time.
Investigation (decision needed on root cause)
- On inspection
1008592205: compare_spectoraJobIdto both Spectora job ids; reviewAutomationEventHistory/ logs for[SpectoraBarebonesSync] createvscreate_success(timing, count). - Confirm company flags at book time (
attikStandalone, scheduler feature flags) and inspection fields (jobCreationType,scheduledLocation, initialstatus). - Decision needed: idempotency strategy (per-inspection lock, atomic claim before
POST, or stricter queue dedupe) and whether orphan Spectora jobs need operational cleanup tooling.
References
- Example work order: https://www.attik.ai/inspections/1008592205?tab=workorder
- Slack: https://attik-talk.slack.com/archives/C0AQFEHRWG6/p1779109676495849
- Key paths:
attik-frontend/src/app/scheduler/summary/BookingJobLoader.tsx;attik-backend/src/util/functions/inspection/createInspection.ts;attik-backend/src/util/functions/spectora/syncBarebonesSpectoraJob.ts;attik-backend/src/events/streamHandlers/inspectionStream.ts;attik-backend/src/routes/webhooks/spectora/syncInspection.ts