@adaptware/eagles-db 0.4.14 → 0.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +5 -105
  2. package/client/edge.js +202 -88
  3. package/client/index-browser.js +197 -83
  4. package/client/index.d.ts +51665 -31859
  5. package/client/index.js +202 -88
  6. package/client/package.json +1 -1
  7. package/client/schema.prisma +419 -212
  8. package/client/wasm.js +197 -83
  9. package/package.json +1 -1
  10. package/prisma/.DS_Store +0 -0
  11. package/prisma/schema/applications.prisma +6 -4
  12. package/prisma/schema/assessmentLibrary.prisma +14 -14
  13. package/prisma/schema/assignment.prisma +42 -36
  14. package/prisma/schema/calendly.prisma +13 -13
  15. package/prisma/schema/communication.prisma +156 -0
  16. package/prisma/schema/document.prisma +37 -0
  17. package/prisma/schema/evaluationPlan.prisma +0 -9
  18. package/prisma/schema/google.prisma +11 -11
  19. package/prisma/schema/interview.prisma +3 -0
  20. package/prisma/schema/jobApplicationFields.prisma +37 -0
  21. package/prisma/schema/jobApplicationResponse.prisma +33 -0
  22. package/prisma/schema/jobApplicationTemplate.prisma +30 -0
  23. package/prisma/schema/jobDescription.prisma +34 -33
  24. package/prisma/schema/migrations/20260519120000_interview_deadline/migration.sql +2 -0
  25. package/prisma/schema/migrations/20260520120000_interview_duration_drop_deadline/migration.sql +30 -0
  26. package/prisma/schema/migrations/20260602120000_resume_file_hash_drop_unique/migration.sql +2 -0
  27. package/prisma/schema/migrations/20260603120000_job_application_field_is_mandatory/migration.sql +2 -0
  28. package/prisma/schema/migrations/20260604120000_job_application_response_updated_by_organisation/migration.sql +2 -0
  29. package/prisma/schema/migrations/20260605120000_drop_document_application_id/migration.sql +3 -0
  30. package/prisma/schema/migrations/20260610120000_jaf_template_model/migration.sql +70 -0
  31. package/prisma/schema/migrations/20260610130000_assignment_document_fks/migration.sql +15 -0
  32. package/prisma/schema/migrations/20260610140000_jaf_draft_activation/migration.sql +12 -0
  33. package/prisma/schema/notes.prisma +15 -15
  34. package/prisma/schema/organisation.prisma +34 -30
  35. package/prisma/schema/organisationConfig.prisma +9 -9
  36. package/prisma/schema/refreshToken.prisma +8 -8
  37. package/prisma/schema/resume.prisma +5 -1
  38. package/prisma/schema/user.prisma +1 -1
  39. package/client/libquery_engine-darwin.dylib.node +0 -0
  40. package/prisma/schema/activityEvent.prisma +0 -115
@@ -80,108 +80,6 @@ model Action {
80
80
  @@index([due_date])
81
81
  }
82
82
 
83
- enum ActivityEventType {
84
- APPLICATION_CREATED
85
- APPLICATION_STARTED
86
- APPLICATION_REJECTED
87
- APPLICATION_SHORTLISTED
88
-
89
- ROUND_ASSIGNED
90
- ROUND_STARTED
91
- ROUND_COMPLETED
92
- ROUND_PASSED
93
- ROUND_FAILED
94
- ROUND_SKIPPED
95
-
96
- INTERVIEW_SCHEDULED
97
- INTERVIEW_RESCHEDULED
98
- INTERVIEW_CANCELLED
99
- INTERVIEW_COMPLETED
100
- INTERVIEW_NO_SHOW
101
- INTERVIEW_EVALUATION_PENDING
102
- INTERVIEW_EVALUATED
103
-
104
- FEEDBACK_SUBMITTED
105
-
106
- JOB_CREATED
107
- JOB_PUBLISHED
108
- JOB_CLOSED
109
- JOB_DEACTIVATED
110
-
111
- EVALUATION_PLAN_CREATED
112
- EVALUATION_PLAN_PUBLISHED
113
- EVALUATION_PLAN_DELETED
114
- EVALUATION_PLAN_UPDATED
115
- STATUS_CHANGED
116
-
117
- CUSTOM
118
- }
119
-
120
- enum ActivityEntityType {
121
- APPLICATION
122
-
123
- CANDIDATE
124
-
125
- JOB
126
-
127
- ONGOING_EVALUATION
128
-
129
- EVALUATION_PLAN
130
-
131
- INTERVIEW
132
-
133
- ASSESSMENT
134
-
135
- ORGANISATION
136
-
137
- USER
138
- }
139
-
140
- enum ActivityEntityActorType {
141
- USER
142
-
143
- SYSTEM
144
-
145
- AI_AGENT
146
-
147
- WEBHOOK
148
- }
149
-
150
- model ActivityEvent {
151
- id String @id @default(uuid())
152
-
153
- organisation_id String?
154
-
155
- event_type ActivityEventType
156
-
157
- entity_type ActivityEntityType
158
- entity_id String
159
-
160
- actor_id String?
161
- actor_type ActivityEntityActorType
162
-
163
- related_entities Json?
164
-
165
- snapshot Json?
166
-
167
- payload Json?
168
-
169
- schema_version Int @default(1)
170
-
171
- occurred_at DateTime
172
-
173
- created_at DateTime @default(now())
174
-
175
- organisation Organisation? @relation(fields: [organisation_id], references: [id])
176
-
177
- @@index([organisation_id, occurred_at])
178
- @@index([organisation_id, event_type])
179
- @@index([entity_type, entity_id])
180
- @@index([actor_id])
181
- @@index([occurred_at])
182
- @@map("activity_events")
183
- }
184
-
185
83
  enum ActivityActorType {
186
84
  USER
187
85
  AI
@@ -214,45 +112,47 @@ enum ApplicationStatus {
214
112
  }
215
113
 
216
114
  model Application {
217
- id String @id @default(uuid())
218
- candidate_id String
219
- resume_id String
220
- organisation_id String
221
- job_description_id String
222
- fit_check_score Float?
223
- applied_at DateTime @default(now())
224
- evaluation_plan_id String?
225
- fit_check_id String? @unique
226
- recruiter_id String?
227
- round_no Int @default(0)
115
+ id String @id @default(uuid())
116
+ candidate_id String
117
+ resume_id String
118
+ organisation_id String
119
+ job_description_id String
120
+ fit_check_score Float?
121
+ applied_at DateTime @default(now())
122
+ evaluation_plan_id String?
123
+ fit_check_id String? @unique
124
+ round_no Int @default(0)
125
+ is_jaf_completed Boolean @default(false)
228
126
  //Screening fields
229
- on_notice_period Boolean @default(false)
230
- expected_joining_date DateTime?
231
- current_ctc String?
232
- expected_ctc String?
233
- notice_period Int?
234
- preferred_location String?
127
+ on_notice_period Boolean @default(false)
128
+ expected_joining_date DateTime?
129
+ current_ctc String?
130
+ expected_ctc String?
131
+ notice_period Int?
132
+ preferred_location String?
235
133
  // Relations
236
- fit_check_status FitCheckStatus?
237
- status ApplicationStatus @default(PENDING)
238
- evaluation_plan EvaluationPlan? @relation(fields: [evaluation_plan_id], references: [id])
239
- candidate User @relation(fields: [candidate_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
240
- organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
241
- resume Resume @relation(fields: [resume_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
242
- job_description JobDescription @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
243
- fit_check FitCheck? @relation(fields: [fit_check_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
244
- recruiter User? @relation("ApplicationRecruiter", fields: [recruiter_id], references: [id])
245
- interviews Interview[]
246
- assignments Assignment[]
247
- ongoing_evaluations OngoingEvaluation[]
248
- activity_logs ActivityLog[]
249
- notes Notes[]
134
+ fit_check_status FitCheckStatus?
135
+ status ApplicationStatus @default(PENDING)
136
+ evaluation_plan EvaluationPlan? @relation(fields: [evaluation_plan_id], references: [id])
137
+ candidate User @relation(fields: [candidate_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
138
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
139
+ resume Resume @relation(fields: [resume_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
140
+ job_description JobDescription @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
141
+ fit_check FitCheck? @relation(fields: [fit_check_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
142
+ interviews Interview[]
143
+ assignments Assignment[]
144
+ ongoing_evaluations OngoingEvaluation[]
145
+ activity_logs ActivityLog[]
146
+ notes Notes[]
147
+ job_application_responses JobApplicationResponse[]
148
+ conversations Conversation[]
149
+ communication_messages CommunicationMessage[]
250
150
  // Audit fields
251
- created_at DateTime @default(now())
252
- updated_at DateTime @updatedAt
253
- created_by String
254
- updated_by String
255
- is_active Boolean @default(true)
151
+ created_at DateTime @default(now())
152
+ updated_at DateTime @updatedAt
153
+ created_by String
154
+ updated_by String
155
+ is_active Boolean @default(true)
256
156
 
257
157
  @@unique([candidate_id, job_description_id]) // Ensures candidate applies only once per job
258
158
  @@index([candidate_id])
@@ -373,8 +273,12 @@ model Assignment {
373
273
  feedback Json?
374
274
  status AssignmentStatus @default(AVAILABLE)
375
275
  cancel_reason String?
276
+ /// @deprecated Prefer `solution_document_id` + `Document`.
376
277
  solution_url String?
278
+ /// @deprecated Prefer `zip_document_id` + `Document`.
377
279
  zip_url String?
280
+ solution_document_id String? @unique
281
+ zip_document_id String? @unique
378
282
  scheduled_start_time DateTime?
379
283
  scheduled_end_time DateTime?
380
284
  created_at DateTime @default(now())
@@ -390,6 +294,8 @@ model Assignment {
390
294
  job_description JobDescription @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
391
295
  application Application? @relation(fields: [application_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
392
296
  ongoing_evaluation OngoingEvaluation? @relation(fields: [ongoing_evaluation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
297
+ solution_document Document? @relation("AssignmentSolutionDocument", fields: [solution_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
298
+ zip_document Document? @relation("AssignmentZipDocument", fields: [zip_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
393
299
 
394
300
  @@unique([candidate_id, ongoing_evaluation_id])
395
301
  @@index([candidate_id])
@@ -540,6 +446,163 @@ model CandidateProfile {
540
446
  is_active Boolean @default(true)
541
447
  }
542
448
 
449
+ // Multi-channel communication (WhatsApp, Email, SMS, Call) with provider abstraction.
450
+ // Strategy: typed columns for everything stable; JSON only for genuinely variable data.
451
+
452
+ enum CommChannel {
453
+ WHATSAPP
454
+ EMAIL
455
+ SMS
456
+ CALL
457
+ }
458
+
459
+ enum CommProvider {
460
+ META_WHATSAPP
461
+ TWILIO
462
+ GUPSHUP
463
+ MTALKZ
464
+ THREE_SIXTY_DIALOG
465
+ GMAIL
466
+ OUTLOOK
467
+ GENERIC_SMTP
468
+ GENERIC
469
+ }
470
+
471
+ enum CommDirection {
472
+ INBOUND
473
+ OUTBOUND
474
+ }
475
+
476
+ enum CommMessageStatus {
477
+ QUEUED
478
+ SENT
479
+ DELIVERED
480
+ READ
481
+ FAILED
482
+ RECEIVED
483
+ }
484
+
485
+ /// Per-organisation provider selection + (encrypted) credentials for one channel.
486
+ /// `metadata` stores non-secret provider settings (e.g. phone_number_id, waba_id, webhook_verify_token).
487
+ model ChannelProviderConfig {
488
+ id String @id @default(uuid())
489
+ organisation_id String
490
+ channel CommChannel
491
+ provider CommProvider
492
+ /// Encrypted JSON blob of secrets (token, app_secret, …) using integrationTokenCrypto.
493
+ credentials String?
494
+ metadata Json @default("{}")
495
+ is_active Boolean @default(true)
496
+ is_default Boolean @default(true)
497
+
498
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
499
+
500
+ conversations Conversation[]
501
+ messages CommunicationMessage[]
502
+
503
+ created_at DateTime @default(now())
504
+ updated_at DateTime @updatedAt
505
+ created_by String
506
+ updated_by String
507
+
508
+ @@unique([organisation_id, channel, provider])
509
+ @@index([organisation_id, channel])
510
+ @@index([organisation_id, channel, is_active])
511
+ }
512
+
513
+ /// A logical conversation thread with one external party on one channel.
514
+ /// `external_id` is the channel-native identifier (E.164 phone for WhatsApp/SMS, email address for email).
515
+ ///
516
+ /// `application_id` / `job_description_id` are the *current* recruiting scope
517
+ /// the thread is bound to (the recruiter can switch context, but individual
518
+ /// `CommunicationMessage` rows record the scope they were sent under so the
519
+ /// audit trail is preserved). Both nullable so pre-application sourcing
520
+ /// (no application yet, just a JD) still works.
521
+ model Conversation {
522
+ id String @id @default(uuid())
523
+ organisation_id String
524
+ channel CommChannel
525
+ provider CommProvider
526
+ channel_provider_id String?
527
+ external_id String
528
+ contact_user_id String?
529
+ application_id String?
530
+ job_description_id String?
531
+ provider_thread_id String?
532
+ subject String?
533
+ status String @default("open")
534
+ unread_count Int @default(0)
535
+ last_message_at DateTime?
536
+ metadata Json @default("{}")
537
+
538
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
539
+ channel_provider ChannelProviderConfig? @relation(fields: [channel_provider_id], references: [id], onDelete: SetNull)
540
+ application Application? @relation(fields: [application_id], references: [id], onDelete: SetNull)
541
+ job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: SetNull)
542
+ messages CommunicationMessage[]
543
+
544
+ created_at DateTime @default(now())
545
+ updated_at DateTime @updatedAt
546
+ created_by String
547
+ updated_by String
548
+
549
+ @@unique([organisation_id, channel, provider, external_id])
550
+ @@index([organisation_id, channel])
551
+ @@index([organisation_id, last_message_at])
552
+ @@index([external_id])
553
+ @@index([organisation_id, application_id])
554
+ @@index([organisation_id, job_description_id])
555
+ }
556
+
557
+ /// Individual message in a conversation. Inbound + outbound share the same model.
558
+ /// `body` is plain text. `attachments` is a JSON array of media descriptors (no binaries persisted).
559
+ /// `metadata` stores raw provider payloads + interactive payloads for audit/debug.
560
+ ///
561
+ /// `application_id` / `job_description_id` are the recruiting scope this
562
+ /// specific message was sent/received under, captured at the time of the
563
+ /// event (not derived from the parent conversation, since a recruiter may
564
+ /// reuse a thread across multiple applications). Both nullable.
565
+ model CommunicationMessage {
566
+ id String @id @default(uuid())
567
+ conversation_id String
568
+ organisation_id String
569
+ channel CommChannel
570
+ provider CommProvider
571
+ channel_provider_id String?
572
+ direction CommDirection
573
+ status CommMessageStatus
574
+ body String?
575
+ from_identifier String
576
+ to_identifier String
577
+ sender_user_id String?
578
+ application_id String?
579
+ job_description_id String?
580
+ provider_message_id String?
581
+ template_name String?
582
+ attachments Json @default("[]")
583
+ metadata Json @default("{}")
584
+ error String?
585
+ sent_at DateTime?
586
+ delivered_at DateTime?
587
+ read_at DateTime?
588
+
589
+ conversation Conversation @relation(fields: [conversation_id], references: [id], onDelete: Cascade)
590
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
591
+ channel_provider ChannelProviderConfig? @relation(fields: [channel_provider_id], references: [id], onDelete: SetNull)
592
+ application Application? @relation(fields: [application_id], references: [id], onDelete: SetNull)
593
+ job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: SetNull)
594
+
595
+ created_at DateTime @default(now())
596
+ updated_at DateTime @updatedAt
597
+
598
+ @@unique([provider, provider_message_id])
599
+ @@index([conversation_id, created_at])
600
+ @@index([organisation_id, channel, created_at])
601
+ @@index([organisation_id, status])
602
+ @@index([organisation_id, application_id])
603
+ @@index([organisation_id, job_description_id])
604
+ }
605
+
543
606
  model ContactUs {
544
607
  id String @id @default(uuid())
545
608
  name String
@@ -553,6 +616,44 @@ model ContactUs {
553
616
  is_active Boolean @default(true)
554
617
  }
555
618
 
619
+ model Document {
620
+ // Primary key
621
+ id String @id @default(uuid())
622
+ // Foreign keys
623
+ organisation_id String?
624
+ candidate_id String?
625
+ // Data fields
626
+ original_file_name String
627
+ stored_file_name String
628
+ file_extension String?
629
+ s3_bucket String?
630
+ s3_key String?
631
+ mime_type String?
632
+ file_size BigInt?
633
+ file_hash String?
634
+ metadata Json?
635
+ // Audit fields
636
+ created_at DateTime @default(now())
637
+ updated_at DateTime @updatedAt
638
+ created_by String
639
+ updated_by String
640
+ is_active Boolean @default(true)
641
+ // Relations
642
+ organisation Organisation? @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
643
+ candidate User? @relation(fields: [candidate_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
644
+ resume Resume?
645
+ job_description_source JobDescription?
646
+ interview_recording Interview?
647
+ job_application_responses JobApplicationResponse[]
648
+ assignment_solution Assignment? @relation("AssignmentSolutionDocument")
649
+ assignment_zip Assignment? @relation("AssignmentZipDocument")
650
+
651
+ // Indexes
652
+ @@index([candidate_id])
653
+ @@index([organisation_id, candidate_id])
654
+ @@index([file_hash])
655
+ }
656
+
556
657
  enum RoundType {
557
658
  ASSESSMENT
558
659
  INTERVIEW
@@ -560,14 +661,6 @@ enum RoundType {
560
661
  SCREENING
561
662
  }
562
663
 
563
- enum EvaluationCategory {
564
- EXPERIENCE_SCREENING
565
- TECHNICAL_SCREENING
566
- TECHNICAL_INTERVIEW
567
- BUSINESS_ROUND
568
- BEHAVIORAL_ROUND
569
- }
570
-
571
664
  enum EvaluationRoundFormat {
572
665
  // ────────────────
573
666
  // Screening formats
@@ -637,7 +730,6 @@ model EvaluationPlan {
637
730
  duration Int?
638
731
  duration_unit DurationUnit?
639
732
  deadline Int?
640
- category EvaluationCategory?
641
733
  created_by String
642
734
  updated_by String
643
735
  created_at DateTime @default(now())
@@ -897,7 +989,9 @@ model Interview {
897
989
  actual_end_time DateTime?
898
990
  /// Interview length in minutes (source of truth; not derived from schedule window).
899
991
  duration Int?
992
+ /// @deprecated Prefer `recording_document_id` + `Document` (type INTERVIEW_RECORDING).
900
993
  recording_url String?
994
+ recording_document_id String? @unique
901
995
  evaluation_type EvaluationType? @default(TREADSPACE_AI_ASSISTED)
902
996
  ai_assistance_mode AiAssistanceMode? @default(ASSISTED)
903
997
  interview_status InterviewStatus @default(SCHEDULED)
@@ -937,6 +1031,7 @@ model Interview {
937
1031
  candidate User? @relation("CandidateInterviews", fields: [candidate_id], references: [id], onDelete: SetNull)
938
1032
  interviewer User? @relation("InterviewerInterviews", fields: [interviewer_id], references: [id], onDelete: SetNull)
939
1033
  organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1034
+ recording_document Document? @relation(fields: [recording_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
940
1035
  job_description JobDescription @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
941
1036
  resume Resume @relation(fields: [resume_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
942
1037
  evaluation_plan EvaluationPlan? @relation(fields: [evaluation_plan_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
@@ -974,6 +1069,109 @@ model InterviewNotes {
974
1069
  @@index([interview_id])
975
1070
  }
976
1071
 
1072
+ enum JobApplicationFieldType {
1073
+ TEXT
1074
+ NUMBER
1075
+ DATE
1076
+ BOOLEAN
1077
+ MULTI_SELECT
1078
+ FILE
1079
+ DROP_DOWN
1080
+ }
1081
+
1082
+ model JobApplicationField {
1083
+ /// Primary key (UUID)
1084
+ id String @id @default(uuid())
1085
+ /// Foreign keys
1086
+ organisation_id String
1087
+ template_id String
1088
+ /// Data fields
1089
+ field_type JobApplicationFieldType
1090
+ label String
1091
+ description String?
1092
+ is_mandatory Boolean @default(false)
1093
+ is_draft Boolean @default(true)
1094
+ options String[]
1095
+ /// Audit fields
1096
+ is_active Boolean @default(true)
1097
+ created_by String
1098
+ updated_by String
1099
+ created_at DateTime @default(now())
1100
+ updated_at DateTime @updatedAt
1101
+ /// Relations
1102
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1103
+ job_application_template JobApplicationTemplate @relation(fields: [template_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1104
+ job_application_responses JobApplicationResponse[]
1105
+
1106
+ /// Indexes
1107
+ @@index([organisation_id, template_id])
1108
+ }
1109
+
1110
+ model JobApplicationResponse {
1111
+ /// Primary key
1112
+ id String @id @default(uuid())
1113
+ /// Foreign keys
1114
+ application_id String
1115
+ job_application_field_id String?
1116
+ document_id String?
1117
+ /// Answer payload
1118
+ response Json?
1119
+ /// Denormalized question snapshot (immutable on candidate save)
1120
+ field_type JobApplicationFieldType?
1121
+ label String?
1122
+ description String?
1123
+ is_mandatory Boolean?
1124
+ is_draft Boolean?
1125
+ is_submitted Boolean @default(false)
1126
+ options String[]
1127
+ updated_by_organisation Boolean @default(false)
1128
+ /// Audit fields
1129
+ created_at DateTime @default(now())
1130
+ updated_at DateTime @updatedAt
1131
+ created_by String
1132
+ updated_by String
1133
+ is_active Boolean @default(true)
1134
+ /// Relations
1135
+ application Application @relation(fields: [application_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1136
+ field JobApplicationField? @relation(fields: [job_application_field_id], references: [id], onDelete: Restrict, onUpdate: Cascade)
1137
+ document Document? @relation(fields: [document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1138
+
1139
+ /// Partial unique on (application_id, job_application_field_id) WHERE job_application_field_id IS NOT NULL — see migration SQL
1140
+ @@index([application_id])
1141
+ @@index([job_application_field_id])
1142
+ }
1143
+
1144
+ enum JobApplicationTemplateScope {
1145
+ ORGANIZATION
1146
+ JOB
1147
+ }
1148
+
1149
+ model JobApplicationTemplate {
1150
+ /// Primary key
1151
+ id String @id @default(uuid())
1152
+ /// Foreign keys
1153
+ organisation_id String
1154
+ job_description_id String? @unique
1155
+ /// Data fields
1156
+ name String
1157
+ description String?
1158
+ scope JobApplicationTemplateScope @default(ORGANIZATION)
1159
+ /// Audit fields
1160
+ is_active Boolean @default(true)
1161
+ created_by String
1162
+ updated_by String
1163
+ created_at DateTime @default(now())
1164
+ updated_at DateTime @updatedAt
1165
+ /// Relations
1166
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1167
+ job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1168
+ fields JobApplicationField[]
1169
+
1170
+ /// Indexes
1171
+ @@index([organisation_id, scope])
1172
+ @@index([job_description_id])
1173
+ }
1174
+
977
1175
  enum JobDescriptionStatus {
978
1176
  CREATED
979
1177
  DRAFT
@@ -983,48 +1181,49 @@ enum JobDescriptionStatus {
983
1181
  }
984
1182
 
985
1183
  model JobDescription {
986
- id String @id @default(uuid())
1184
+ id String @id @default(uuid())
987
1185
  organisation_id String
988
1186
  hiring_manager_id String?
989
- status JobDescriptionStatus @default(DRAFT)
1187
+ status JobDescriptionStatus @default(DRAFT)
990
1188
  screeningQuestions String[]
991
1189
  recommendedQuestions Json[]
1190
+ /// @deprecated Prefer `source_document_id` + `Document` (type JOB_DESCRIPTION).
992
1191
  uploaded_job_description_path String?
993
- is_plan_published Boolean @default(false)
994
- is_posted Boolean @default(false)
1192
+ source_document_id String? @unique
1193
+ is_plan_published Boolean @default(false)
1194
+ is_posted Boolean @default(false)
995
1195
  summary Json?
996
1196
  ai_insight Json?
997
1197
  job_fit_comparison Json?
998
- target_closing_date DateTime?
999
- closing_date DateTime?
1000
-
1001
- job_number Int?
1002
- job_code String? @unique
1003
1198
  // Audit fields
1004
- created_at DateTime @default(now())
1005
- updated_at DateTime @updatedAt
1006
- created_by String
1007
- updated_by String
1008
- is_active Boolean @default(true)
1009
- openings Int @default(1)
1010
- job_profile_id String?
1011
- job_profile JobProfile? @relation(fields: [job_profile_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1012
- organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1013
- applications Application[]
1014
- interviews Interview[]
1015
- assignments Assignment[]
1016
- fit_check FitCheck[] // one-to-many link
1017
- job_description_data JobDescriptionData[] // one-to-many link
1018
- evaluationPlan EvaluationPlan[] // relation to evaluation methods
1019
- ongoing_evaluations OngoingEvaluation[] // optional one-to-many
1020
- assignment_library AssignmentLibrary[]
1021
- approvals Approval[] // one-to-many relation
1022
- resumes Resume[] // one-to-many link
1023
- budget Budget?
1024
- hiring_manager User? @relation("HiringManager", fields: [hiring_manager_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1025
- recruiters User[]
1026
- transcripts Transcript[]
1027
- integration_job_syncs IntegrationJobSync[]
1199
+ created_at DateTime @default(now())
1200
+ updated_at DateTime @updatedAt
1201
+ created_by String
1202
+ updated_by String
1203
+ is_active Boolean @default(true)
1204
+ openings Int @default(1)
1205
+ job_profile_id String?
1206
+ job_profile JobProfile? @relation(fields: [job_profile_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1207
+ organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
1208
+ source_document Document? @relation(fields: [source_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1209
+ applications Application[]
1210
+ interviews Interview[]
1211
+ assignments Assignment[]
1212
+ fit_check FitCheck[] // one-to-many link
1213
+ job_description_data JobDescriptionData[] // one-to-many link
1214
+ evaluationPlan EvaluationPlan[] // relation to evaluation methods
1215
+ ongoing_evaluations OngoingEvaluation[] // optional one-to-many
1216
+ assignment_library AssignmentLibrary[]
1217
+ approvals Approval[] // one-to-many relation
1218
+ resumes Resume[] // one-to-many link
1219
+ budget Budget?
1220
+ hiring_manager User? @relation("HiringManager", fields: [hiring_manager_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1221
+ recruiters User[]
1222
+ transcripts Transcript[]
1223
+ integration_job_syncs IntegrationJobSync[]
1224
+ job_application_template JobApplicationTemplate?
1225
+ conversations Conversation[]
1226
+ communication_messages CommunicationMessage[]
1028
1227
 
1029
1228
  @@index([organisation_id])
1030
1229
  @@index([hiring_manager_id])
@@ -1251,36 +1450,40 @@ model Organisation {
1251
1450
  company_values Json[]
1252
1451
  allowed_email_domains String[]
1253
1452
 
1254
- interviewers User[]
1255
- created_at DateTime @default(now())
1256
- updated_at DateTime @updatedAt
1257
- created_by String
1258
- updated_by String
1259
- is_active Boolean @default(true)
1260
- alias String? @unique
1261
- logo String?
1262
- org_code String? @unique
1263
- job_sequence Int @default(1)
1264
- applications Application[]
1265
- user_roles UserRole[]
1266
- job_descriptions JobDescription[]
1267
- job_profiles JobProfile[]
1268
- assessment_library AssessmentLibrary[]
1269
- assignment_library AssignmentLibrary[]
1270
- interviews Interview[]
1271
- assignments Assignment[]
1272
- fit_check FitCheck[] // one-to-many link
1273
- resumes Resume[] // one-to-many link
1274
- approvals Approval[] // one-to-many link
1275
- suggestions Suggestion[]
1276
- ongoing_evaluations OngoingEvaluation[] // optional one-to-many
1277
- actions Action[]
1278
- integration_credentials IntegrationCredential[]
1279
- zoho_sync_mappings ZohoSyncMapping[]
1280
- assessments Assessment[]
1281
- timezone String @default("Asia/Kolkata")
1282
- organisation_configs OrganisationConfig[]
1283
- activity_events ActivityEvent[]
1453
+ interviewers User[]
1454
+ created_at DateTime @default(now())
1455
+ updated_at DateTime @updatedAt
1456
+ created_by String
1457
+ updated_by String
1458
+ is_active Boolean @default(true)
1459
+ alias String? @unique
1460
+ logo String?
1461
+ applications Application[]
1462
+ user_roles UserRole[]
1463
+ job_descriptions JobDescription[]
1464
+ job_profiles JobProfile[]
1465
+ assessment_library AssessmentLibrary[]
1466
+ assignment_library AssignmentLibrary[]
1467
+ interviews Interview[]
1468
+ assignments Assignment[]
1469
+ fit_check FitCheck[] // one-to-many link
1470
+ resumes Resume[] // one-to-many link
1471
+ approvals Approval[] // one-to-many link
1472
+ suggestions Suggestion[]
1473
+ ongoing_evaluations OngoingEvaluation[] // optional one-to-many
1474
+ actions Action[]
1475
+ integration_credentials IntegrationCredential[]
1476
+ zoho_sync_mappings ZohoSyncMapping[]
1477
+ assessments Assessment[]
1478
+ timezone String @default("Asia/Kolkata")
1479
+ organisation_configs OrganisationConfig[]
1480
+ job_application_fields JobApplicationField[]
1481
+ documents Document[]
1482
+ job_application_templates JobApplicationTemplate[]
1483
+
1484
+ channel_provider_configs ChannelProviderConfig[]
1485
+ conversations Conversation[]
1486
+ communication_messages CommunicationMessage[]
1284
1487
 
1285
1488
  @@index([name])
1286
1489
  }
@@ -1397,8 +1600,11 @@ model Resume {
1397
1600
  user_id String?
1398
1601
  organisation_id String?
1399
1602
  job_description_id String?
1603
+ /// @deprecated Prefer `document_id` + `Document`. Kept until backfill completes.
1400
1604
  uploaded_resume_path String?
1401
- file_hash String? @unique
1605
+ document_id String? @unique
1606
+ /// @deprecated Prefer `Document.file_hash`. Kept for legacy read fallback.
1607
+ file_hash String?
1402
1608
  summary Json?
1403
1609
  created_at DateTime @default(now())
1404
1610
  updated_at DateTime @updatedAt
@@ -1409,6 +1615,7 @@ model Resume {
1409
1615
  user User? @relation(fields: [user_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1410
1616
  organisation Organisation? @relation(fields: [organisation_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1411
1617
  job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1618
+ document Document? @relation(fields: [document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
1412
1619
  applications Application[]
1413
1620
  interviews Interview[]
1414
1621
  ongoing_evaluations OngoingEvaluation[] // optional one-to-many
@@ -1572,7 +1779,6 @@ model User {
1572
1779
  refresh_token_auth RefreshToken[] @relation("TokenRefresh")
1573
1780
  zoom_meeting_participants ZoomMeetingParticipant[]
1574
1781
  notes Notes[]
1575
- recruiter_applications Application[] @relation("ApplicationRecruiter")
1576
1782
 
1577
1783
  name String?
1578
1784
  phone String?
@@ -1591,6 +1797,7 @@ model User {
1591
1797
  veteran_status String?
1592
1798
  disability_status String?
1593
1799
  professional_expertise String?
1800
+ documents Document[]
1594
1801
 
1595
1802
  @@index([role_id])
1596
1803
  @@index([permission_id])