@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.
- package/README.md +5 -105
- package/client/edge.js +202 -88
- package/client/index-browser.js +197 -83
- package/client/index.d.ts +51665 -31859
- package/client/index.js +202 -88
- package/client/package.json +1 -1
- package/client/schema.prisma +419 -212
- package/client/wasm.js +197 -83
- package/package.json +1 -1
- package/prisma/.DS_Store +0 -0
- package/prisma/schema/applications.prisma +6 -4
- package/prisma/schema/assessmentLibrary.prisma +14 -14
- package/prisma/schema/assignment.prisma +42 -36
- package/prisma/schema/calendly.prisma +13 -13
- package/prisma/schema/communication.prisma +156 -0
- package/prisma/schema/document.prisma +37 -0
- package/prisma/schema/evaluationPlan.prisma +0 -9
- package/prisma/schema/google.prisma +11 -11
- package/prisma/schema/interview.prisma +3 -0
- package/prisma/schema/jobApplicationFields.prisma +37 -0
- package/prisma/schema/jobApplicationResponse.prisma +33 -0
- package/prisma/schema/jobApplicationTemplate.prisma +30 -0
- package/prisma/schema/jobDescription.prisma +34 -33
- package/prisma/schema/migrations/20260519120000_interview_deadline/migration.sql +2 -0
- package/prisma/schema/migrations/20260520120000_interview_duration_drop_deadline/migration.sql +30 -0
- package/prisma/schema/migrations/20260602120000_resume_file_hash_drop_unique/migration.sql +2 -0
- package/prisma/schema/migrations/20260603120000_job_application_field_is_mandatory/migration.sql +2 -0
- package/prisma/schema/migrations/20260604120000_job_application_response_updated_by_organisation/migration.sql +2 -0
- package/prisma/schema/migrations/20260605120000_drop_document_application_id/migration.sql +3 -0
- package/prisma/schema/migrations/20260610120000_jaf_template_model/migration.sql +70 -0
- package/prisma/schema/migrations/20260610130000_assignment_document_fks/migration.sql +15 -0
- package/prisma/schema/migrations/20260610140000_jaf_draft_activation/migration.sql +12 -0
- package/prisma/schema/notes.prisma +15 -15
- package/prisma/schema/organisation.prisma +34 -30
- package/prisma/schema/organisationConfig.prisma +9 -9
- package/prisma/schema/refreshToken.prisma +8 -8
- package/prisma/schema/resume.prisma +5 -1
- package/prisma/schema/user.prisma +1 -1
- package/client/libquery_engine-darwin.dylib.node +0 -0
- package/prisma/schema/activityEvent.prisma +0 -115
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Multi-channel communication (WhatsApp, Email, SMS, Call) with provider abstraction.
|
|
2
|
+
// Strategy: typed columns for everything stable; JSON only for genuinely variable data.
|
|
3
|
+
|
|
4
|
+
enum CommChannel {
|
|
5
|
+
WHATSAPP
|
|
6
|
+
EMAIL
|
|
7
|
+
SMS
|
|
8
|
+
CALL
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
enum CommProvider {
|
|
12
|
+
META_WHATSAPP
|
|
13
|
+
TWILIO
|
|
14
|
+
GUPSHUP
|
|
15
|
+
MTALKZ
|
|
16
|
+
THREE_SIXTY_DIALOG
|
|
17
|
+
GMAIL
|
|
18
|
+
OUTLOOK
|
|
19
|
+
GENERIC_SMTP
|
|
20
|
+
GENERIC
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
enum CommDirection {
|
|
24
|
+
INBOUND
|
|
25
|
+
OUTBOUND
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
enum CommMessageStatus {
|
|
29
|
+
QUEUED
|
|
30
|
+
SENT
|
|
31
|
+
DELIVERED
|
|
32
|
+
READ
|
|
33
|
+
FAILED
|
|
34
|
+
RECEIVED
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Per-organisation provider selection + (encrypted) credentials for one channel.
|
|
38
|
+
/// `metadata` stores non-secret provider settings (e.g. phone_number_id, waba_id, webhook_verify_token).
|
|
39
|
+
model ChannelProviderConfig {
|
|
40
|
+
id String @id @default(uuid())
|
|
41
|
+
organisation_id String
|
|
42
|
+
channel CommChannel
|
|
43
|
+
provider CommProvider
|
|
44
|
+
/// Encrypted JSON blob of secrets (token, app_secret, …) using integrationTokenCrypto.
|
|
45
|
+
credentials String?
|
|
46
|
+
metadata Json @default("{}")
|
|
47
|
+
is_active Boolean @default(true)
|
|
48
|
+
is_default Boolean @default(true)
|
|
49
|
+
|
|
50
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
|
|
51
|
+
|
|
52
|
+
conversations Conversation[]
|
|
53
|
+
messages CommunicationMessage[]
|
|
54
|
+
|
|
55
|
+
created_at DateTime @default(now())
|
|
56
|
+
updated_at DateTime @updatedAt
|
|
57
|
+
created_by String
|
|
58
|
+
updated_by String
|
|
59
|
+
|
|
60
|
+
@@unique([organisation_id, channel, provider])
|
|
61
|
+
@@index([organisation_id, channel])
|
|
62
|
+
@@index([organisation_id, channel, is_active])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// A logical conversation thread with one external party on one channel.
|
|
66
|
+
/// `external_id` is the channel-native identifier (E.164 phone for WhatsApp/SMS, email address for email).
|
|
67
|
+
///
|
|
68
|
+
/// `application_id` / `job_description_id` are the *current* recruiting scope
|
|
69
|
+
/// the thread is bound to (the recruiter can switch context, but individual
|
|
70
|
+
/// `CommunicationMessage` rows record the scope they were sent under so the
|
|
71
|
+
/// audit trail is preserved). Both nullable so pre-application sourcing
|
|
72
|
+
/// (no application yet, just a JD) still works.
|
|
73
|
+
model Conversation {
|
|
74
|
+
id String @id @default(uuid())
|
|
75
|
+
organisation_id String
|
|
76
|
+
channel CommChannel
|
|
77
|
+
provider CommProvider
|
|
78
|
+
channel_provider_id String?
|
|
79
|
+
external_id String
|
|
80
|
+
contact_user_id String?
|
|
81
|
+
application_id String?
|
|
82
|
+
job_description_id String?
|
|
83
|
+
provider_thread_id String?
|
|
84
|
+
subject String?
|
|
85
|
+
status String @default("open")
|
|
86
|
+
unread_count Int @default(0)
|
|
87
|
+
last_message_at DateTime?
|
|
88
|
+
metadata Json @default("{}")
|
|
89
|
+
|
|
90
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
|
|
91
|
+
channel_provider ChannelProviderConfig? @relation(fields: [channel_provider_id], references: [id], onDelete: SetNull)
|
|
92
|
+
application Application? @relation(fields: [application_id], references: [id], onDelete: SetNull)
|
|
93
|
+
job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: SetNull)
|
|
94
|
+
messages CommunicationMessage[]
|
|
95
|
+
|
|
96
|
+
created_at DateTime @default(now())
|
|
97
|
+
updated_at DateTime @updatedAt
|
|
98
|
+
created_by String
|
|
99
|
+
updated_by String
|
|
100
|
+
|
|
101
|
+
@@unique([organisation_id, channel, provider, external_id])
|
|
102
|
+
@@index([organisation_id, channel])
|
|
103
|
+
@@index([organisation_id, last_message_at])
|
|
104
|
+
@@index([external_id])
|
|
105
|
+
@@index([organisation_id, application_id])
|
|
106
|
+
@@index([organisation_id, job_description_id])
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// Individual message in a conversation. Inbound + outbound share the same model.
|
|
110
|
+
/// `body` is plain text. `attachments` is a JSON array of media descriptors (no binaries persisted).
|
|
111
|
+
/// `metadata` stores raw provider payloads + interactive payloads for audit/debug.
|
|
112
|
+
///
|
|
113
|
+
/// `application_id` / `job_description_id` are the recruiting scope this
|
|
114
|
+
/// specific message was sent/received under, captured at the time of the
|
|
115
|
+
/// event (not derived from the parent conversation, since a recruiter may
|
|
116
|
+
/// reuse a thread across multiple applications). Both nullable.
|
|
117
|
+
model CommunicationMessage {
|
|
118
|
+
id String @id @default(uuid())
|
|
119
|
+
conversation_id String
|
|
120
|
+
organisation_id String
|
|
121
|
+
channel CommChannel
|
|
122
|
+
provider CommProvider
|
|
123
|
+
channel_provider_id String?
|
|
124
|
+
direction CommDirection
|
|
125
|
+
status CommMessageStatus
|
|
126
|
+
body String?
|
|
127
|
+
from_identifier String
|
|
128
|
+
to_identifier String
|
|
129
|
+
sender_user_id String?
|
|
130
|
+
application_id String?
|
|
131
|
+
job_description_id String?
|
|
132
|
+
provider_message_id String?
|
|
133
|
+
template_name String?
|
|
134
|
+
attachments Json @default("[]")
|
|
135
|
+
metadata Json @default("{}")
|
|
136
|
+
error String?
|
|
137
|
+
sent_at DateTime?
|
|
138
|
+
delivered_at DateTime?
|
|
139
|
+
read_at DateTime?
|
|
140
|
+
|
|
141
|
+
conversation Conversation @relation(fields: [conversation_id], references: [id], onDelete: Cascade)
|
|
142
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade)
|
|
143
|
+
channel_provider ChannelProviderConfig? @relation(fields: [channel_provider_id], references: [id], onDelete: SetNull)
|
|
144
|
+
application Application? @relation(fields: [application_id], references: [id], onDelete: SetNull)
|
|
145
|
+
job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: SetNull)
|
|
146
|
+
|
|
147
|
+
created_at DateTime @default(now())
|
|
148
|
+
updated_at DateTime @updatedAt
|
|
149
|
+
|
|
150
|
+
@@unique([provider, provider_message_id])
|
|
151
|
+
@@index([conversation_id, created_at])
|
|
152
|
+
@@index([organisation_id, channel, created_at])
|
|
153
|
+
@@index([organisation_id, status])
|
|
154
|
+
@@index([organisation_id, application_id])
|
|
155
|
+
@@index([organisation_id, job_description_id])
|
|
156
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
model Document {
|
|
2
|
+
// Primary key
|
|
3
|
+
id String @id @default(uuid())
|
|
4
|
+
// Foreign keys
|
|
5
|
+
organisation_id String?
|
|
6
|
+
candidate_id String?
|
|
7
|
+
// Data fields
|
|
8
|
+
original_file_name String
|
|
9
|
+
stored_file_name String
|
|
10
|
+
file_extension String?
|
|
11
|
+
s3_bucket String?
|
|
12
|
+
s3_key String?
|
|
13
|
+
mime_type String?
|
|
14
|
+
file_size BigInt?
|
|
15
|
+
file_hash String?
|
|
16
|
+
metadata Json?
|
|
17
|
+
// Audit fields
|
|
18
|
+
created_at DateTime @default(now())
|
|
19
|
+
updated_at DateTime @updatedAt
|
|
20
|
+
created_by String
|
|
21
|
+
updated_by String
|
|
22
|
+
is_active Boolean @default(true)
|
|
23
|
+
// Relations
|
|
24
|
+
organisation Organisation? @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
25
|
+
candidate User? @relation(fields: [candidate_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
26
|
+
resume Resume?
|
|
27
|
+
job_description_source JobDescription?
|
|
28
|
+
interview_recording Interview?
|
|
29
|
+
job_application_responses JobApplicationResponse[]
|
|
30
|
+
assignment_solution Assignment? @relation("AssignmentSolutionDocument")
|
|
31
|
+
assignment_zip Assignment? @relation("AssignmentZipDocument")
|
|
32
|
+
|
|
33
|
+
// Indexes
|
|
34
|
+
@@index([candidate_id])
|
|
35
|
+
@@index([organisation_id, candidate_id])
|
|
36
|
+
@@index([file_hash])
|
|
37
|
+
}
|
|
@@ -5,14 +5,6 @@ enum RoundType {
|
|
|
5
5
|
SCREENING
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
enum EvaluationCategory {
|
|
9
|
-
EXPERIENCE_SCREENING
|
|
10
|
-
TECHNICAL_SCREENING
|
|
11
|
-
TECHNICAL_INTERVIEW
|
|
12
|
-
BUSINESS_ROUND
|
|
13
|
-
BEHAVIORAL_ROUND
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
enum EvaluationRoundFormat {
|
|
17
9
|
// ────────────────
|
|
18
10
|
// Screening formats
|
|
@@ -82,7 +74,6 @@ model EvaluationPlan {
|
|
|
82
74
|
duration Int?
|
|
83
75
|
duration_unit DurationUnit?
|
|
84
76
|
deadline Int?
|
|
85
|
-
category EvaluationCategory?
|
|
86
77
|
created_by String
|
|
87
78
|
updated_by String
|
|
88
79
|
created_at DateTime @default(now())
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
model Google {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
user_id String @unique
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
google_email String
|
|
6
|
+
refresh_token String
|
|
7
|
+
scope String?
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
user User @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
created_at DateTime @default(now())
|
|
12
|
+
updated_at DateTime @updatedAt
|
|
13
|
+
created_by String
|
|
14
|
+
updated_by String
|
|
15
|
+
is_active Boolean @default(true)
|
|
16
16
|
}
|
|
@@ -45,7 +45,9 @@ model Interview {
|
|
|
45
45
|
actual_end_time DateTime?
|
|
46
46
|
/// Interview length in minutes (source of truth; not derived from schedule window).
|
|
47
47
|
duration Int?
|
|
48
|
+
/// @deprecated Prefer `recording_document_id` + `Document` (type INTERVIEW_RECORDING).
|
|
48
49
|
recording_url String?
|
|
50
|
+
recording_document_id String? @unique
|
|
49
51
|
evaluation_type EvaluationType? @default(TREADSPACE_AI_ASSISTED)
|
|
50
52
|
ai_assistance_mode AiAssistanceMode? @default(ASSISTED)
|
|
51
53
|
interview_status InterviewStatus @default(SCHEDULED)
|
|
@@ -85,6 +87,7 @@ model Interview {
|
|
|
85
87
|
candidate User? @relation("CandidateInterviews", fields: [candidate_id], references: [id], onDelete: SetNull)
|
|
86
88
|
interviewer User? @relation("InterviewerInterviews", fields: [interviewer_id], references: [id], onDelete: SetNull)
|
|
87
89
|
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
90
|
+
recording_document Document? @relation(fields: [recording_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
88
91
|
job_description JobDescription @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
89
92
|
resume Resume @relation(fields: [resume_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
90
93
|
evaluation_plan EvaluationPlan? @relation(fields: [evaluation_plan_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
enum JobApplicationFieldType {
|
|
2
|
+
TEXT
|
|
3
|
+
NUMBER
|
|
4
|
+
DATE
|
|
5
|
+
BOOLEAN
|
|
6
|
+
MULTI_SELECT
|
|
7
|
+
FILE
|
|
8
|
+
DROP_DOWN
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
model JobApplicationField {
|
|
12
|
+
/// Primary key (UUID)
|
|
13
|
+
id String @id @default(uuid())
|
|
14
|
+
/// Foreign keys
|
|
15
|
+
organisation_id String
|
|
16
|
+
template_id String
|
|
17
|
+
/// Data fields
|
|
18
|
+
field_type JobApplicationFieldType
|
|
19
|
+
label String
|
|
20
|
+
description String?
|
|
21
|
+
is_mandatory Boolean @default(false)
|
|
22
|
+
is_draft Boolean @default(true)
|
|
23
|
+
options String[]
|
|
24
|
+
/// Audit fields
|
|
25
|
+
is_active Boolean @default(true)
|
|
26
|
+
created_by String
|
|
27
|
+
updated_by String
|
|
28
|
+
created_at DateTime @default(now())
|
|
29
|
+
updated_at DateTime @updatedAt
|
|
30
|
+
/// Relations
|
|
31
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
32
|
+
job_application_template JobApplicationTemplate @relation(fields: [template_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
33
|
+
job_application_responses JobApplicationResponse[]
|
|
34
|
+
|
|
35
|
+
/// Indexes
|
|
36
|
+
@@index([organisation_id, template_id])
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
model JobApplicationResponse {
|
|
2
|
+
/// Primary key
|
|
3
|
+
id String @id @default(uuid())
|
|
4
|
+
/// Foreign keys
|
|
5
|
+
application_id String
|
|
6
|
+
job_application_field_id String?
|
|
7
|
+
document_id String?
|
|
8
|
+
/// Answer payload
|
|
9
|
+
response Json?
|
|
10
|
+
/// Denormalized question snapshot (immutable on candidate save)
|
|
11
|
+
field_type JobApplicationFieldType?
|
|
12
|
+
label String?
|
|
13
|
+
description String?
|
|
14
|
+
is_mandatory Boolean?
|
|
15
|
+
is_draft Boolean?
|
|
16
|
+
is_submitted Boolean @default(false)
|
|
17
|
+
options String[]
|
|
18
|
+
updated_by_organisation Boolean @default(false)
|
|
19
|
+
/// Audit fields
|
|
20
|
+
created_at DateTime @default(now())
|
|
21
|
+
updated_at DateTime @updatedAt
|
|
22
|
+
created_by String
|
|
23
|
+
updated_by String
|
|
24
|
+
is_active Boolean @default(true)
|
|
25
|
+
/// Relations
|
|
26
|
+
application Application @relation(fields: [application_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
27
|
+
field JobApplicationField? @relation(fields: [job_application_field_id], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
|
28
|
+
document Document? @relation(fields: [document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
29
|
+
|
|
30
|
+
/// Partial unique on (application_id, job_application_field_id) WHERE job_application_field_id IS NOT NULL — see migration SQL
|
|
31
|
+
@@index([application_id])
|
|
32
|
+
@@index([job_application_field_id])
|
|
33
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
enum JobApplicationTemplateScope {
|
|
2
|
+
ORGANIZATION
|
|
3
|
+
JOB
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
model JobApplicationTemplate {
|
|
7
|
+
/// Primary key
|
|
8
|
+
id String @id @default(uuid())
|
|
9
|
+
/// Foreign keys
|
|
10
|
+
organisation_id String
|
|
11
|
+
job_description_id String? @unique
|
|
12
|
+
/// Data fields
|
|
13
|
+
name String
|
|
14
|
+
description String?
|
|
15
|
+
scope JobApplicationTemplateScope @default(ORGANIZATION)
|
|
16
|
+
/// Audit fields
|
|
17
|
+
is_active Boolean @default(true)
|
|
18
|
+
created_by String
|
|
19
|
+
updated_by String
|
|
20
|
+
created_at DateTime @default(now())
|
|
21
|
+
updated_at DateTime @updatedAt
|
|
22
|
+
/// Relations
|
|
23
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
24
|
+
job_description JobDescription? @relation(fields: [job_description_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
25
|
+
fields JobApplicationField[]
|
|
26
|
+
|
|
27
|
+
/// Indexes
|
|
28
|
+
@@index([organisation_id, scope])
|
|
29
|
+
@@index([job_description_id])
|
|
30
|
+
}
|
|
@@ -7,48 +7,49 @@ enum JobDescriptionStatus {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
model JobDescription {
|
|
10
|
-
id String
|
|
10
|
+
id String @id @default(uuid())
|
|
11
11
|
organisation_id String
|
|
12
12
|
hiring_manager_id String?
|
|
13
|
-
status JobDescriptionStatus
|
|
13
|
+
status JobDescriptionStatus @default(DRAFT)
|
|
14
14
|
screeningQuestions String[]
|
|
15
15
|
recommendedQuestions Json[]
|
|
16
|
+
/// @deprecated Prefer `source_document_id` + `Document` (type JOB_DESCRIPTION).
|
|
16
17
|
uploaded_job_description_path String?
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
source_document_id String? @unique
|
|
19
|
+
is_plan_published Boolean @default(false)
|
|
20
|
+
is_posted Boolean @default(false)
|
|
19
21
|
summary Json?
|
|
20
22
|
ai_insight Json?
|
|
21
23
|
job_fit_comparison Json?
|
|
22
|
-
target_closing_date DateTime?
|
|
23
|
-
closing_date DateTime?
|
|
24
|
-
|
|
25
|
-
job_number Int?
|
|
26
|
-
job_code String? @unique
|
|
27
24
|
// Audit fields
|
|
28
|
-
created_at
|
|
29
|
-
updated_at
|
|
30
|
-
created_by
|
|
31
|
-
updated_by
|
|
32
|
-
is_active
|
|
33
|
-
openings
|
|
34
|
-
job_profile_id
|
|
35
|
-
job_profile
|
|
36
|
-
organisation
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
25
|
+
created_at DateTime @default(now())
|
|
26
|
+
updated_at DateTime @updatedAt
|
|
27
|
+
created_by String
|
|
28
|
+
updated_by String
|
|
29
|
+
is_active Boolean @default(true)
|
|
30
|
+
openings Int @default(1)
|
|
31
|
+
job_profile_id String?
|
|
32
|
+
job_profile JobProfile? @relation(fields: [job_profile_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
33
|
+
organisation Organisation @relation(fields: [organisation_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
34
|
+
source_document Document? @relation(fields: [source_document_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
35
|
+
applications Application[]
|
|
36
|
+
interviews Interview[]
|
|
37
|
+
assignments Assignment[]
|
|
38
|
+
fit_check FitCheck[] // one-to-many link
|
|
39
|
+
job_description_data JobDescriptionData[] // one-to-many link
|
|
40
|
+
evaluationPlan EvaluationPlan[] // relation to evaluation methods
|
|
41
|
+
ongoing_evaluations OngoingEvaluation[] // optional one-to-many
|
|
42
|
+
assignment_library AssignmentLibrary[]
|
|
43
|
+
approvals Approval[] // one-to-many relation
|
|
44
|
+
resumes Resume[] // one-to-many link
|
|
45
|
+
budget Budget?
|
|
46
|
+
hiring_manager User? @relation("HiringManager", fields: [hiring_manager_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
47
|
+
recruiters User[]
|
|
48
|
+
transcripts Transcript[]
|
|
49
|
+
integration_job_syncs IntegrationJobSync[]
|
|
50
|
+
job_application_template JobApplicationTemplate?
|
|
51
|
+
conversations Conversation[]
|
|
52
|
+
communication_messages CommunicationMessage[]
|
|
52
53
|
|
|
53
54
|
@@index([organisation_id])
|
|
54
55
|
@@index([hiring_manager_id])
|
package/prisma/schema/migrations/20260520120000_interview_duration_drop_deadline/migration.sql
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Interview.duration (minutes) replaces timestamp-derived length; Interview.deadline removed (window = scheduled_end_time).
|
|
2
|
+
ALTER TABLE "Interview" ADD COLUMN IF NOT EXISTS "duration" INTEGER;
|
|
3
|
+
|
|
4
|
+
ALTER TABLE "Interview" DROP COLUMN IF EXISTS "deadline";
|
|
5
|
+
|
|
6
|
+
-- Best-effort inline backfill (Full AI rows may be wrong until backfill-interview-duration.ts runs).
|
|
7
|
+
UPDATE "Interview" i
|
|
8
|
+
SET "duration" = GREATEST(
|
|
9
|
+
1,
|
|
10
|
+
ROUND(
|
|
11
|
+
EXTRACT(EPOCH FROM (i."scheduled_end_time" - i."scheduled_start_time")) / 60
|
|
12
|
+
)::integer
|
|
13
|
+
)
|
|
14
|
+
WHERE i."duration" IS NULL
|
|
15
|
+
AND i."scheduled_start_time" IS NOT NULL
|
|
16
|
+
AND i."scheduled_end_time" IS NOT NULL
|
|
17
|
+
AND i."scheduled_end_time" > i."scheduled_start_time"
|
|
18
|
+
AND (i."evaluation_type" IS NULL OR i."evaluation_type"::text <> 'TREADSPACE_FULL_AI');
|
|
19
|
+
|
|
20
|
+
UPDATE "Interview" i
|
|
21
|
+
SET "duration" = oe."duration"
|
|
22
|
+
FROM "OngoingEvaluation" oe
|
|
23
|
+
WHERE oe."interview_id" = i."id"
|
|
24
|
+
AND i."duration" IS NULL
|
|
25
|
+
AND oe."duration" IS NOT NULL
|
|
26
|
+
AND oe."duration_unit" = 'MINUTES';
|
|
27
|
+
|
|
28
|
+
UPDATE "Interview"
|
|
29
|
+
SET "duration" = 45
|
|
30
|
+
WHERE "duration" IS NULL;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
-- CreateEnum
|
|
2
|
+
CREATE TYPE "JobApplicationTemplateScope" AS ENUM ('ORGANIZATION', 'JOB');
|
|
3
|
+
|
|
4
|
+
-- CreateTable
|
|
5
|
+
CREATE TABLE "JobApplicationTemplate" (
|
|
6
|
+
"id" TEXT NOT NULL,
|
|
7
|
+
"organisation_id" TEXT NOT NULL,
|
|
8
|
+
"job_description_id" TEXT,
|
|
9
|
+
"name" TEXT NOT NULL,
|
|
10
|
+
"description" TEXT,
|
|
11
|
+
"scope" "JobApplicationTemplateScope" NOT NULL DEFAULT 'ORGANIZATION',
|
|
12
|
+
"is_active" BOOLEAN NOT NULL DEFAULT true,
|
|
13
|
+
"created_by" TEXT NOT NULL,
|
|
14
|
+
"updated_by" TEXT NOT NULL,
|
|
15
|
+
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
16
|
+
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
17
|
+
|
|
18
|
+
CONSTRAINT "JobApplicationTemplate_pkey" PRIMARY KEY ("id")
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- Drop legacy scope model on JobApplicationField (greenfield — no data backfill)
|
|
22
|
+
ALTER TABLE "JobApplicationField" DROP CONSTRAINT IF EXISTS "JobApplicationField_job_description_id_fkey";
|
|
23
|
+
ALTER TABLE "JobApplicationField" DROP CONSTRAINT IF EXISTS "JobApplicationField_application_id_fkey";
|
|
24
|
+
DROP INDEX IF EXISTS "JobApplicationField_organisation_id_scope_idx";
|
|
25
|
+
DROP INDEX IF EXISTS "JobApplicationField_job_description_id_idx";
|
|
26
|
+
DROP INDEX IF EXISTS "JobApplicationField_application_id_idx";
|
|
27
|
+
|
|
28
|
+
ALTER TABLE "JobApplicationField" DROP COLUMN IF EXISTS "scope";
|
|
29
|
+
ALTER TABLE "JobApplicationField" DROP COLUMN IF EXISTS "job_description_id";
|
|
30
|
+
ALTER TABLE "JobApplicationField" DROP COLUMN IF EXISTS "application_id";
|
|
31
|
+
|
|
32
|
+
DROP TYPE IF EXISTS "JobApplicationFieldScope";
|
|
33
|
+
|
|
34
|
+
ALTER TABLE "JobApplicationField" ADD COLUMN IF NOT EXISTS "template_id" TEXT;
|
|
35
|
+
|
|
36
|
+
-- JobApplicationResponse snapshot columns
|
|
37
|
+
ALTER TABLE "JobApplicationResponse" DROP CONSTRAINT IF EXISTS "JobApplicationResponse_job_application_field_id_fkey";
|
|
38
|
+
DROP INDEX IF EXISTS "JobApplicationResponse_application_id_job_application_field_id_key";
|
|
39
|
+
|
|
40
|
+
ALTER TABLE "JobApplicationResponse" ALTER COLUMN "job_application_field_id" DROP NOT NULL;
|
|
41
|
+
|
|
42
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "field_type" "JobApplicationFieldType";
|
|
43
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "label" TEXT;
|
|
44
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "description" TEXT;
|
|
45
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "is_mandatory" BOOLEAN;
|
|
46
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "options" TEXT[] DEFAULT ARRAY[]::TEXT[];
|
|
47
|
+
|
|
48
|
+
-- Document: remove application link
|
|
49
|
+
ALTER TABLE "Document" DROP CONSTRAINT IF EXISTS "Document_application_id_fkey";
|
|
50
|
+
DROP INDEX IF EXISTS "Document_application_id_idx";
|
|
51
|
+
ALTER TABLE "Document" DROP COLUMN IF EXISTS "application_id";
|
|
52
|
+
|
|
53
|
+
-- Greenfield: no legacy JAF rows — clear any orphan fields before NOT NULL
|
|
54
|
+
DELETE FROM "JobApplicationField";
|
|
55
|
+
ALTER TABLE "JobApplicationField" ALTER COLUMN "template_id" SET NOT NULL;
|
|
56
|
+
|
|
57
|
+
-- Indexes and foreign keys
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "JobApplicationTemplate_job_description_id_key" ON "JobApplicationTemplate"("job_description_id");
|
|
59
|
+
CREATE INDEX IF NOT EXISTS "JobApplicationTemplate_organisation_id_scope_idx" ON "JobApplicationTemplate"("organisation_id", "scope");
|
|
60
|
+
CREATE INDEX IF NOT EXISTS "JobApplicationTemplate_job_description_id_idx" ON "JobApplicationTemplate"("job_description_id");
|
|
61
|
+
|
|
62
|
+
ALTER TABLE "JobApplicationTemplate" ADD CONSTRAINT "JobApplicationTemplate_organisation_id_fkey" FOREIGN KEY ("organisation_id") REFERENCES "Organisation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
63
|
+
ALTER TABLE "JobApplicationTemplate" ADD CONSTRAINT "JobApplicationTemplate_job_description_id_fkey" FOREIGN KEY ("job_description_id") REFERENCES "JobDescription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
64
|
+
|
|
65
|
+
ALTER TABLE "JobApplicationField" ADD CONSTRAINT "JobApplicationField_template_id_fkey" FOREIGN KEY ("template_id") REFERENCES "JobApplicationTemplate"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
66
|
+
CREATE INDEX IF NOT EXISTS "JobApplicationField_organisation_id_template_id_idx" ON "JobApplicationField"("organisation_id", "template_id");
|
|
67
|
+
|
|
68
|
+
ALTER TABLE "JobApplicationResponse" ADD CONSTRAINT "JobApplicationResponse_job_application_field_id_fkey" FOREIGN KEY ("job_application_field_id") REFERENCES "JobApplicationField"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
69
|
+
|
|
70
|
+
CREATE UNIQUE INDEX "JobApplicationResponse_application_id_job_application_field_id_key" ON "JobApplicationResponse"("application_id", "job_application_field_id") WHERE "job_application_field_id" IS NOT NULL;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- AlterTable
|
|
2
|
+
ALTER TABLE "Assignment" ADD COLUMN "solution_document_id" TEXT,
|
|
3
|
+
ADD COLUMN "zip_document_id" TEXT;
|
|
4
|
+
|
|
5
|
+
-- CreateIndex
|
|
6
|
+
CREATE UNIQUE INDEX "Assignment_solution_document_id_key" ON "Assignment"("solution_document_id");
|
|
7
|
+
|
|
8
|
+
-- CreateIndex
|
|
9
|
+
CREATE UNIQUE INDEX "Assignment_zip_document_id_key" ON "Assignment"("zip_document_id");
|
|
10
|
+
|
|
11
|
+
-- AddForeignKey
|
|
12
|
+
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_solution_document_id_fkey" FOREIGN KEY ("solution_document_id") REFERENCES "Document"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
13
|
+
|
|
14
|
+
-- AddForeignKey
|
|
15
|
+
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_zip_document_id_fkey" FOREIGN KEY ("zip_document_id") REFERENCES "Document"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- JobApplicationField: draft gate for template/job fields
|
|
2
|
+
ALTER TABLE "JobApplicationField" ADD COLUMN IF NOT EXISTS "is_draft" BOOLEAN DEFAULT true;
|
|
3
|
+
UPDATE "JobApplicationField" SET "is_draft" = false WHERE "is_draft" IS NULL;
|
|
4
|
+
ALTER TABLE "JobApplicationField" ALTER COLUMN "is_draft" SET NOT NULL;
|
|
5
|
+
ALTER TABLE "JobApplicationField" ALTER COLUMN "is_draft" SET DEFAULT true;
|
|
6
|
+
|
|
7
|
+
-- JobApplicationResponse: per-row draft/submit state
|
|
8
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "is_draft" BOOLEAN;
|
|
9
|
+
ALTER TABLE "JobApplicationResponse" ADD COLUMN IF NOT EXISTS "is_submitted" BOOLEAN DEFAULT false;
|
|
10
|
+
UPDATE "JobApplicationResponse" SET "is_draft" = false WHERE "is_draft" IS NULL;
|
|
11
|
+
UPDATE "JobApplicationResponse" SET "is_submitted" = false WHERE "is_submitted" IS NULL;
|
|
12
|
+
ALTER TABLE "JobApplicationResponse" ALTER COLUMN "is_draft" SET DEFAULT false;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
model Notes {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
application_id String
|
|
4
|
+
user_id String
|
|
5
|
+
note String
|
|
6
|
+
pinned Boolean @default(false)
|
|
7
|
+
created_at DateTime @default(now())
|
|
8
|
+
updated_at DateTime @updatedAt
|
|
9
|
+
created_by String
|
|
10
|
+
updated_by String
|
|
11
|
+
is_active Boolean @default(true)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
// Relations
|
|
14
|
+
application Application @relation(fields: [application_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
15
|
+
user User @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
@@index([application_id, created_at])
|
|
18
|
+
@@index([user_id, created_at])
|
|
19
19
|
}
|