4
0

integrations.prisma 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /// One installed connector for one organisation: the account it is linked
  2. /// to, its sealed credentials, and the settings the workshop chose. Rows in
  3. /// the other integration tables hang off this one.
  4. model IntegrationConnection {
  5. id String @id @default(cuid())
  6. organizationId String
  7. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  8. /// Connector id from the registry, for example 'google-calendar'.
  9. connectorId String
  10. /// pending | active | error | disconnected
  11. status String @default("pending")
  12. label String?
  13. /// Tokens or keys as one sealed string; only the vault reads it.
  14. credentials String?
  15. settings Json @default("{}")
  16. /// Connector-owned state such as sync cursors and last-run times.
  17. state Json @default("{}")
  18. externalAccountId String?
  19. externalAccountName String?
  20. scopes String?
  21. /// OAuth handshake nonce, set while the connection is pending.
  22. oauthState String? @unique
  23. lastHealthAt DateTime?
  24. lastSyncAt DateTime?
  25. lastError String?
  26. createdById String
  27. createdAt DateTime @default(now())
  28. updatedAt DateTime @updatedAt
  29. links IntegrationLink[]
  30. jobs IntegrationJob[]
  31. logs IntegrationLog[]
  32. externalEvents ExternalCalendarEvent[]
  33. @@unique([organizationId, connectorId])
  34. @@index([organizationId])
  35. @@map("integration_connections")
  36. }
  37. /// The remote id a local record has in one connected system, which is what
  38. /// makes every push an update instead of a duplicate.
  39. model IntegrationLink {
  40. id String @id @default(cuid())
  41. connectionId String
  42. connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  43. /// Local model name, for example 'ServiceRecord'.
  44. entityType String
  45. entityId String
  46. remoteId String
  47. remoteUrl String?
  48. /// Connector-owned extras, such as a meeting link.
  49. metadata Json?
  50. checksum String?
  51. remoteUpdatedAt DateTime?
  52. lastSyncedAt DateTime @default(now())
  53. createdAt DateTime @default(now())
  54. @@unique([connectionId, entityType, entityId])
  55. @@index([connectionId, remoteId])
  56. @@index([entityType, entityId])
  57. @@map("integration_links")
  58. }
  59. /// A unit of work for a connector, claimed and retried by the cron.
  60. model IntegrationJob {
  61. id String @id @default(cuid())
  62. connectionId String
  63. connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  64. organizationId String
  65. kind String
  66. payload Json?
  67. /// Set while the job is pending so the same work is queued once; cleared when it runs.
  68. idempotencyKey String?
  69. /// queued | running | done | failed | dead
  70. status String @default("queued")
  71. attempts Int @default(0)
  72. maxAttempts Int @default(5)
  73. runAfter DateTime @default(now())
  74. lockedAt DateTime?
  75. startedAt DateTime?
  76. finishedAt DateTime?
  77. error String?
  78. createdAt DateTime @default(now())
  79. updatedAt DateTime @updatedAt
  80. @@unique([connectionId, idempotencyKey])
  81. @@index([status, runAfter])
  82. @@index([connectionId, createdAt])
  83. @@index([organizationId, createdAt])
  84. @@map("integration_jobs")
  85. }
  86. /// What a connector did and why it failed, per connection, kept for 30 days.
  87. model IntegrationLog {
  88. id String @id @default(cuid())
  89. connectionId String
  90. connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  91. jobId String?
  92. /// info | warn | error
  93. level String @default("info")
  94. message String
  95. details Json?
  96. createdAt DateTime @default(now())
  97. @@index([connectionId, createdAt])
  98. @@map("integration_logs")
  99. }
  100. /// Busy time pulled from a connected calendar, shown read-only on the
  101. /// workshop calendar. A cache: rebuilt by the pull job, never edited.
  102. model ExternalCalendarEvent {
  103. id String @id @default(cuid())
  104. connectionId String
  105. connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  106. organizationId String
  107. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  108. remoteId String
  109. calendarId String
  110. title String
  111. startAt DateTime
  112. endAt DateTime
  113. allDay Boolean @default(false)
  114. /// The event's page in the vendor's own calendar, when the vendor gives one.
  115. remoteUrl String?
  116. remoteUpdatedAt DateTime?
  117. createdAt DateTime @default(now())
  118. updatedAt DateTime @updatedAt
  119. @@unique([connectionId, remoteId])
  120. @@index([organizationId, startAt])
  121. @@map("external_calendar_events")
  122. }
  123. /// What a safety authority knows about one model year: recalls, owner
  124. /// complaints and crash ratings, as the connector shaped them. Public data,
  125. /// keyed by model rather than by workshop or vehicle, so a 2003 Accord is
  126. /// fetched once for everyone. A cache: rebuilt by the connector, never edited.
  127. model VehicleSafetyReport {
  128. id String @id @default(cuid())
  129. /// Connector id, such as "nhtsa".
  130. source String
  131. /// Make, model and year as the workshop wrote them, upper-cased and trimmed.
  132. make String
  133. model String
  134. year Int
  135. /// False when the authority answered but had no such model.
  136. found Boolean @default(true)
  137. data Json
  138. /// Counts lifted out of data so a list can show a badge without parsing it.
  139. recallCount Int @default(0)
  140. complaintCount Int @default(0)
  141. fetchedAt DateTime @default(now())
  142. createdAt DateTime @default(now())
  143. @@unique([source, make, model, year])
  144. @@index([fetchedAt])
  145. @@map("vehicle_safety_reports")
  146. }