2024-03-20 15:42:17 +02:00
|
|
|
generator kysely {
|
|
|
|
|
provider = "prisma-kysely"
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generator client {
|
2023-08-25 17:51:58 +10:00
|
|
|
provider = "prisma-client-js"
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-05 22:14:47 +09:00
|
|
|
generator zod {
|
|
|
|
|
provider = "zod-prisma-types"
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-07 15:10:26 +01:00
|
|
|
datasource db {
|
2023-08-25 17:51:58 +10:00
|
|
|
provider = "postgresql"
|
|
|
|
|
url = env("NEXT_PRIVATE_DATABASE_URL")
|
|
|
|
|
directUrl = env("NEXT_PRIVATE_DIRECT_DATABASE_URL")
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-19 12:49:09 +01:00
|
|
|
enum IdentityProvider {
|
|
|
|
|
DOCUMENSO
|
|
|
|
|
GOOGLE
|
2024-04-13 20:46:08 -04:00
|
|
|
OIDC
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-08 09:16:31 +03:00
|
|
|
enum Role {
|
|
|
|
|
ADMIN
|
|
|
|
|
USER
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-07 15:10:26 +01:00
|
|
|
model User {
|
2024-06-27 21:50:42 +10:00
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
name String?
|
|
|
|
|
customerId String? @unique
|
|
|
|
|
email String @unique
|
|
|
|
|
emailVerified DateTime?
|
|
|
|
|
password String?
|
|
|
|
|
source String?
|
|
|
|
|
signature String?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
|
|
|
lastSignedIn DateTime @default(now())
|
|
|
|
|
roles Role[] @default([USER])
|
|
|
|
|
identityProvider IdentityProvider @default(DOCUMENSO)
|
|
|
|
|
avatarImageId String?
|
|
|
|
|
|
2023-12-01 05:52:16 +05:30
|
|
|
accounts Account[]
|
|
|
|
|
sessions Session[]
|
|
|
|
|
Document Document[]
|
2023-12-14 15:22:54 +11:00
|
|
|
Subscription Subscription[]
|
2023-12-01 05:52:16 +05:30
|
|
|
PasswordResetToken PasswordResetToken[]
|
2024-02-06 16:16:10 +11:00
|
|
|
ownedTeams Team[]
|
|
|
|
|
ownedPendingTeams TeamPending[]
|
|
|
|
|
teamMembers TeamMember[]
|
2023-12-01 05:52:16 +05:30
|
|
|
twoFactorSecret String?
|
2024-02-22 01:57:46 +05:30
|
|
|
twoFactorEnabled Boolean @default(false)
|
2023-12-01 05:52:16 +05:30
|
|
|
twoFactorBackupCodes String?
|
2024-02-28 14:43:09 +11:00
|
|
|
url String? @unique
|
2024-02-22 01:57:46 +05:30
|
|
|
|
2024-06-06 14:46:48 +10:00
|
|
|
profile UserProfile?
|
2024-01-30 17:31:27 +11:00
|
|
|
VerificationToken VerificationToken[]
|
2024-02-26 00:21:25 +11:00
|
|
|
ApiToken ApiToken[]
|
2024-01-30 17:31:27 +11:00
|
|
|
Template Template[]
|
|
|
|
|
securityAuditLogs UserSecurityAuditLog[]
|
2024-02-06 16:00:28 +02:00
|
|
|
Webhooks Webhook[]
|
2024-02-23 10:47:01 +00:00
|
|
|
siteSettings SiteSettings[]
|
2024-03-26 21:11:59 +08:00
|
|
|
passkeys Passkey[]
|
2024-06-27 21:50:42 +10:00
|
|
|
avatarImage AvatarImage? @relation(fields: [avatarImageId], references: [id], onDelete: SetNull)
|
2023-11-23 15:21:13 +02:00
|
|
|
|
2023-10-30 16:58:51 +11:00
|
|
|
@@index([email])
|
2023-09-18 06:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-22 01:57:46 +05:30
|
|
|
model UserProfile {
|
2024-06-06 14:46:48 +10:00
|
|
|
id String @id @default(cuid())
|
|
|
|
|
enabled Boolean @default(false)
|
|
|
|
|
userId Int @unique
|
|
|
|
|
bio String?
|
2024-02-22 01:57:46 +05:30
|
|
|
|
2024-06-06 14:46:48 +10:00
|
|
|
User User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamProfile {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
enabled Boolean @default(false)
|
|
|
|
|
teamId Int @unique
|
|
|
|
|
bio String?
|
|
|
|
|
|
|
|
|
|
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
2024-02-22 01:57:46 +05:30
|
|
|
}
|
|
|
|
|
|
2024-01-30 17:31:27 +11:00
|
|
|
enum UserSecurityAuditLogType {
|
|
|
|
|
ACCOUNT_PROFILE_UPDATE
|
|
|
|
|
ACCOUNT_SSO_LINK
|
|
|
|
|
AUTH_2FA_DISABLE
|
|
|
|
|
AUTH_2FA_ENABLE
|
2024-03-26 21:11:59 +08:00
|
|
|
PASSKEY_CREATED
|
|
|
|
|
PASSKEY_DELETED
|
|
|
|
|
PASSKEY_UPDATED
|
2024-01-30 17:31:27 +11:00
|
|
|
PASSWORD_RESET
|
|
|
|
|
PASSWORD_UPDATE
|
|
|
|
|
SIGN_OUT
|
|
|
|
|
SIGN_IN
|
2024-01-31 12:27:40 +11:00
|
|
|
SIGN_IN_FAIL
|
|
|
|
|
SIGN_IN_2FA_FAIL
|
2024-03-26 21:11:59 +08:00
|
|
|
SIGN_IN_PASSKEY_FAIL
|
2024-01-30 17:31:27 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model UserSecurityAuditLog {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
userId Int
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
type UserSecurityAuditLogType
|
|
|
|
|
userAgent String?
|
|
|
|
|
ipAddress String?
|
|
|
|
|
|
2024-01-30 18:37:48 +11:00
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2024-01-30 17:31:27 +11:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 06:47:03 +00:00
|
|
|
model PasswordResetToken {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
token String @unique
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
expiry DateTime
|
|
|
|
|
userId Int
|
2024-04-24 17:32:11 +10:00
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2023-05-05 19:29:42 +10:00
|
|
|
}
|
|
|
|
|
|
2024-03-26 21:11:59 +08:00
|
|
|
model Passkey {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
userId Int
|
|
|
|
|
name String
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @default(now())
|
|
|
|
|
lastUsedAt DateTime?
|
|
|
|
|
credentialId Bytes
|
|
|
|
|
credentialPublicKey Bytes
|
|
|
|
|
counter BigInt
|
|
|
|
|
credentialDeviceType String
|
|
|
|
|
credentialBackedUp Boolean
|
|
|
|
|
transports String[]
|
|
|
|
|
|
|
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model AnonymousVerificationToken {
|
|
|
|
|
id String @id @unique @default(cuid())
|
|
|
|
|
token String @unique
|
|
|
|
|
expiresAt DateTime
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-21 06:42:29 +02:00
|
|
|
model VerificationToken {
|
2024-03-31 15:49:12 +08:00
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
secondaryId String @unique @default(cuid())
|
|
|
|
|
identifier String
|
|
|
|
|
token String @unique
|
2024-08-28 14:08:35 +10:00
|
|
|
completed Boolean @default(false)
|
2024-03-31 15:49:12 +08:00
|
|
|
expires DateTime
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
userId Int
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2023-11-21 06:42:29 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-06 16:00:28 +02:00
|
|
|
enum WebhookTriggerEvents {
|
|
|
|
|
DOCUMENT_CREATED
|
2024-02-24 11:18:58 +02:00
|
|
|
DOCUMENT_SENT
|
|
|
|
|
DOCUMENT_OPENED
|
2024-02-06 16:00:28 +02:00
|
|
|
DOCUMENT_SIGNED
|
2024-02-24 11:18:58 +02:00
|
|
|
DOCUMENT_COMPLETED
|
2024-12-04 14:35:20 +11:00
|
|
|
DOCUMENT_REJECTED
|
2024-02-06 16:00:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Webhook {
|
2024-02-27 12:13:56 +11:00
|
|
|
id String @id @default(cuid())
|
2024-02-06 16:00:28 +02:00
|
|
|
webhookUrl String
|
|
|
|
|
eventTriggers WebhookTriggerEvents[]
|
|
|
|
|
secret String?
|
|
|
|
|
enabled Boolean @default(true)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
|
|
|
userId Int
|
|
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2024-02-27 13:38:12 +11:00
|
|
|
teamId Int?
|
|
|
|
|
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
2024-02-27 12:54:37 +11:00
|
|
|
WebhookCall WebhookCall[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum WebhookCallStatus {
|
|
|
|
|
SUCCESS
|
|
|
|
|
FAILED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model WebhookCall {
|
2024-02-27 15:16:14 +11:00
|
|
|
id String @id @default(cuid())
|
2024-02-27 12:54:37 +11:00
|
|
|
status WebhookCallStatus
|
|
|
|
|
url String
|
2024-02-27 15:16:14 +11:00
|
|
|
event WebhookTriggerEvents
|
2024-02-27 12:54:37 +11:00
|
|
|
requestBody Json
|
|
|
|
|
responseCode Int
|
|
|
|
|
responseHeaders Json?
|
|
|
|
|
responseBody Json?
|
2024-02-27 15:16:14 +11:00
|
|
|
createdAt DateTime @default(now())
|
2024-02-27 12:54:37 +11:00
|
|
|
webhookId String
|
2024-02-27 15:16:14 +11:00
|
|
|
webhook Webhook @relation(fields: [webhookId], references: [id], onDelete: Cascade)
|
2024-02-06 16:00:28 +02:00
|
|
|
}
|
|
|
|
|
|
2023-11-23 15:21:13 +02:00
|
|
|
enum ApiTokenAlgorithm {
|
|
|
|
|
SHA512
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model ApiToken {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
name String
|
|
|
|
|
token String @unique
|
|
|
|
|
algorithm ApiTokenAlgorithm @default(SHA512)
|
2024-02-09 11:32:54 +02:00
|
|
|
expires DateTime?
|
2023-11-23 15:21:13 +02:00
|
|
|
createdAt DateTime @default(now())
|
2024-02-22 13:39:34 +11:00
|
|
|
userId Int?
|
|
|
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
teamId Int?
|
|
|
|
|
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
2023-11-23 15:21:13 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-05 19:29:42 +10:00
|
|
|
enum SubscriptionStatus {
|
|
|
|
|
ACTIVE
|
|
|
|
|
PAST_DUE
|
|
|
|
|
INACTIVE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Subscription {
|
2023-09-18 22:33:07 +10:00
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
status SubscriptionStatus @default(INACTIVE)
|
2023-12-14 15:22:54 +11:00
|
|
|
planId String @unique
|
|
|
|
|
priceId String
|
2023-09-18 22:33:07 +10:00
|
|
|
periodEnd DateTime?
|
2024-02-06 16:16:10 +11:00
|
|
|
userId Int?
|
|
|
|
|
teamId Int? @unique
|
2023-09-18 22:33:07 +10:00
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
cancelAtPeriodEnd Boolean @default(false)
|
2023-05-05 19:29:42 +10:00
|
|
|
|
2024-02-06 16:16:10 +11:00
|
|
|
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
User User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2023-05-05 19:29:42 +10:00
|
|
|
|
|
|
|
|
@@index([userId])
|
2023-01-10 18:52:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Account {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
userId Int
|
|
|
|
|
type String
|
|
|
|
|
provider String
|
|
|
|
|
providerAccountId String
|
|
|
|
|
refresh_token String? @db.Text
|
|
|
|
|
access_token String? @db.Text
|
|
|
|
|
expires_at Int?
|
2024-05-30 22:15:45 +10:00
|
|
|
// Some providers return created_at so we need to make it optional
|
|
|
|
|
created_at Int?
|
|
|
|
|
// Stops next-auth from crashing when dealing with AzureAD
|
|
|
|
|
ext_expires_in Int?
|
2023-01-10 18:52:04 +01:00
|
|
|
token_type String?
|
|
|
|
|
scope String?
|
|
|
|
|
id_token String? @db.Text
|
|
|
|
|
session_state String?
|
|
|
|
|
|
|
|
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
|
|
@@unique([provider, providerAccountId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Session {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
sessionToken String @unique
|
|
|
|
|
userId Int
|
|
|
|
|
expires DateTime
|
|
|
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 12:49:09 +01:00
|
|
|
enum DocumentStatus {
|
|
|
|
|
DRAFT
|
|
|
|
|
PENDING
|
|
|
|
|
COMPLETED
|
2023-02-13 19:33:26 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 15:49:09 +10:00
|
|
|
enum DocumentSource {
|
|
|
|
|
DOCUMENT
|
|
|
|
|
TEMPLATE
|
|
|
|
|
TEMPLATE_DIRECT_LINK
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-16 17:14:16 +03:00
|
|
|
enum DocumentVisibility {
|
|
|
|
|
EVERYONE
|
|
|
|
|
MANAGER_AND_ABOVE
|
|
|
|
|
ADMIN
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 12:49:09 +01:00
|
|
|
model Document {
|
2023-09-21 00:51:02 +00:00
|
|
|
id Int @id @default(autoincrement())
|
2024-07-13 16:45:09 +10:00
|
|
|
externalId String?
|
2023-09-21 00:51:02 +00:00
|
|
|
userId Int
|
|
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2024-03-28 13:13:29 +08:00
|
|
|
authOptions Json?
|
2024-04-08 17:01:11 +07:00
|
|
|
formValues Json?
|
2024-09-16 17:14:16 +03:00
|
|
|
visibility DocumentVisibility @default(EVERYONE)
|
2023-09-21 00:51:02 +00:00
|
|
|
title String
|
|
|
|
|
status DocumentStatus @default(DRAFT)
|
|
|
|
|
Recipient Recipient[]
|
|
|
|
|
Field Field[]
|
|
|
|
|
ShareLink DocumentShareLink[]
|
|
|
|
|
documentDataId String
|
2023-10-28 20:57:26 +11:00
|
|
|
documentData DocumentData @relation(fields: [documentDataId], references: [id], onDelete: Cascade)
|
2023-09-22 12:27:54 +00:00
|
|
|
documentMeta DocumentMeta?
|
2023-10-28 20:57:26 +11:00
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @default(now()) @updatedAt
|
2023-11-03 15:48:19 +11:00
|
|
|
completedAt DateTime?
|
2023-12-06 05:41:51 +05:30
|
|
|
deletedAt DateTime?
|
2024-02-06 16:16:10 +11:00
|
|
|
teamId Int?
|
|
|
|
|
team Team? @relation(fields: [teamId], references: [id])
|
2024-06-02 15:49:09 +10:00
|
|
|
templateId Int?
|
|
|
|
|
template Template? @relation(fields: [templateId], references: [id], onDelete: SetNull)
|
|
|
|
|
source DocumentSource
|
2023-09-20 08:57:50 +00:00
|
|
|
|
2024-02-12 12:04:53 +11:00
|
|
|
auditLogs DocumentAuditLog[]
|
|
|
|
|
|
2023-09-21 00:51:02 +00:00
|
|
|
@@unique([documentDataId])
|
2023-10-30 16:58:51 +11:00
|
|
|
@@index([userId])
|
|
|
|
|
@@index([status])
|
2023-09-21 00:51:02 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-12 12:04:53 +11:00
|
|
|
model DocumentAuditLog {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
documentId Int
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
type String
|
|
|
|
|
data Json
|
|
|
|
|
|
|
|
|
|
// Details of the person who performed the action which caused the audit log.
|
|
|
|
|
name String?
|
|
|
|
|
email String?
|
|
|
|
|
userId Int?
|
|
|
|
|
userAgent String?
|
|
|
|
|
ipAddress String?
|
|
|
|
|
|
|
|
|
|
Document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 00:51:02 +00:00
|
|
|
enum DocumentDataType {
|
|
|
|
|
S3_PATH
|
|
|
|
|
BYTES
|
|
|
|
|
BYTES_64
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-16 12:36:45 +00:00
|
|
|
enum DocumentSigningOrder {
|
|
|
|
|
PARALLEL
|
|
|
|
|
SEQUENTIAL
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 00:51:02 +00:00
|
|
|
model DocumentData {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
type DocumentDataType
|
|
|
|
|
data String
|
|
|
|
|
initialData String
|
|
|
|
|
Document Document?
|
2023-10-06 22:54:24 +00:00
|
|
|
Template Template?
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-08 13:32:13 +09:00
|
|
|
enum DocumentDistributionMethod {
|
|
|
|
|
EMAIL
|
|
|
|
|
NONE
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 08:57:50 +00:00
|
|
|
model DocumentMeta {
|
2024-11-08 13:32:13 +09:00
|
|
|
id String @id @default(cuid())
|
2024-10-18 04:25:19 +01:00
|
|
|
subject String?
|
|
|
|
|
message String?
|
2024-11-08 13:32:13 +09:00
|
|
|
timezone String? @default("Etc/UTC") @db.Text
|
2024-10-18 04:25:19 +01:00
|
|
|
password String?
|
2024-11-08 13:32:13 +09:00
|
|
|
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
|
|
|
|
|
documentId Int @unique
|
|
|
|
|
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
2024-10-18 04:25:19 +01:00
|
|
|
redirectUrl String?
|
2024-11-08 13:32:13 +09:00
|
|
|
signingOrder DocumentSigningOrder @default(PARALLEL)
|
2024-11-26 12:03:44 +02:00
|
|
|
typedSignatureEnabled Boolean @default(true)
|
2024-11-08 13:32:13 +09:00
|
|
|
language String @default("en")
|
|
|
|
|
distributionMethod DocumentDistributionMethod @default(EMAIL)
|
|
|
|
|
emailSettings Json?
|
2023-09-20 08:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-07 15:10:26 +01:00
|
|
|
enum ReadStatus {
|
|
|
|
|
NOT_OPENED
|
|
|
|
|
OPENED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum SendStatus {
|
|
|
|
|
NOT_SENT
|
|
|
|
|
SENT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum SigningStatus {
|
|
|
|
|
NOT_SIGNED
|
|
|
|
|
SIGNED
|
2024-11-14 21:37:42 +11:00
|
|
|
REJECTED
|
2023-01-07 15:10:26 +01:00
|
|
|
}
|
2023-01-27 20:14:32 +01:00
|
|
|
|
2024-02-01 18:45:02 -05:00
|
|
|
enum RecipientRole {
|
|
|
|
|
CC
|
|
|
|
|
SIGNER
|
|
|
|
|
VIEWER
|
|
|
|
|
APPROVER
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 12:49:09 +01:00
|
|
|
model Recipient {
|
2024-04-19 17:37:38 +07:00
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
documentId Int?
|
|
|
|
|
templateId Int?
|
|
|
|
|
email String @db.VarChar(255)
|
|
|
|
|
name String @default("") @db.VarChar(255)
|
|
|
|
|
token String
|
|
|
|
|
documentDeletedAt DateTime?
|
|
|
|
|
expired DateTime?
|
|
|
|
|
signedAt DateTime?
|
|
|
|
|
authOptions Json?
|
2024-09-16 12:36:45 +00:00
|
|
|
signingOrder Int?
|
2024-11-14 21:37:42 +11:00
|
|
|
rejectionReason String?
|
2024-04-19 17:37:38 +07:00
|
|
|
role RecipientRole @default(SIGNER)
|
|
|
|
|
readStatus ReadStatus @default(NOT_OPENED)
|
|
|
|
|
signingStatus SigningStatus @default(NOT_SIGNED)
|
|
|
|
|
sendStatus SendStatus @default(NOT_SENT)
|
|
|
|
|
Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
|
|
|
Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
|
Field Field[]
|
|
|
|
|
Signature Signature[]
|
2023-06-21 23:49:23 +10:00
|
|
|
|
|
|
|
|
@@unique([documentId, email])
|
2023-10-06 22:54:24 +00:00
|
|
|
@@unique([templateId, email])
|
2023-10-30 16:58:51 +11:00
|
|
|
@@index([documentId])
|
2023-10-06 22:54:24 +00:00
|
|
|
@@index([templateId])
|
2023-10-30 16:58:51 +11:00
|
|
|
@@index([token])
|
2023-02-19 12:49:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum FieldType {
|
|
|
|
|
SIGNATURE
|
2023-02-24 16:12:56 +01:00
|
|
|
FREE_SIGNATURE
|
2024-08-12 15:29:32 +02:00
|
|
|
INITIALS
|
2023-06-21 23:49:23 +10:00
|
|
|
NAME
|
|
|
|
|
EMAIL
|
2023-02-19 12:49:09 +01:00
|
|
|
DATE
|
|
|
|
|
TEXT
|
2024-07-18 16:45:44 +03:00
|
|
|
NUMBER
|
|
|
|
|
RADIO
|
|
|
|
|
CHECKBOX
|
|
|
|
|
DROPDOWN
|
2023-02-19 12:49:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Field {
|
|
|
|
|
id Int @id @default(autoincrement())
|
2024-02-12 12:04:53 +11:00
|
|
|
secondaryId String @unique @default(cuid())
|
2023-10-06 22:54:24 +00:00
|
|
|
documentId Int?
|
|
|
|
|
templateId Int?
|
2024-04-18 21:56:31 +07:00
|
|
|
recipientId Int
|
2023-02-19 12:49:09 +01:00
|
|
|
type FieldType
|
|
|
|
|
page Int
|
2023-06-23 12:20:49 +00:00
|
|
|
positionX Decimal @default(0)
|
|
|
|
|
positionY Decimal @default(0)
|
|
|
|
|
width Decimal @default(-1)
|
|
|
|
|
height Decimal @default(-1)
|
2023-02-28 19:36:21 +01:00
|
|
|
customText String
|
2023-03-09 13:43:05 +01:00
|
|
|
inserted Boolean
|
2023-10-06 22:54:24 +00:00
|
|
|
Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
|
|
|
Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
2024-04-18 21:56:31 +07:00
|
|
|
Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
2023-02-19 12:49:09 +01:00
|
|
|
Signature Signature?
|
2024-07-18 16:45:44 +03:00
|
|
|
fieldMeta Json?
|
2023-10-30 16:58:51 +11:00
|
|
|
|
|
|
|
|
@@index([documentId])
|
2023-10-06 22:54:24 +00:00
|
|
|
@@index([templateId])
|
2023-10-30 16:58:51 +11:00
|
|
|
@@index([recipientId])
|
2023-02-19 12:49:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Signature {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
created DateTime @default(now())
|
|
|
|
|
recipientId Int
|
|
|
|
|
fieldId Int @unique
|
2023-02-20 18:14:52 +01:00
|
|
|
signatureImageAsBase64 String?
|
|
|
|
|
typedSignature String?
|
2023-02-19 12:49:09 +01:00
|
|
|
|
2023-04-06 21:26:26 -04:00
|
|
|
Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
2024-04-24 17:32:11 +10:00
|
|
|
Field Field @relation(fields: [fieldId], references: [id], onDelete: Cascade)
|
2023-10-30 16:58:51 +11:00
|
|
|
|
|
|
|
|
@@index([recipientId])
|
2023-01-27 20:14:32 +01:00
|
|
|
}
|
2023-06-05 12:23:52 +00:00
|
|
|
|
2023-09-21 00:51:02 +00:00
|
|
|
model DocumentShareLink {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
email String
|
|
|
|
|
slug String @unique
|
|
|
|
|
documentId Int
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
2023-10-13 12:45:39 +11:00
|
|
|
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
2023-09-21 00:51:02 +00:00
|
|
|
|
|
|
|
|
@@unique([documentId, email])
|
2023-06-05 12:23:52 +00:00
|
|
|
}
|
2023-10-06 22:54:24 +00:00
|
|
|
|
2024-02-06 16:16:10 +11:00
|
|
|
enum TeamMemberRole {
|
|
|
|
|
ADMIN
|
|
|
|
|
MANAGER
|
|
|
|
|
MEMBER
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum TeamMemberInviteStatus {
|
|
|
|
|
ACCEPTED
|
|
|
|
|
PENDING
|
2024-07-25 04:27:19 +00:00
|
|
|
DECLINED
|
2024-02-06 16:16:10 +11:00
|
|
|
}
|
|
|
|
|
|
feat: add global settings for teams (#1391)
## Description
This PR introduces global settings for teams. At the moment, it allows
team admins to configure the following:
* The default visibility of the documents uploaded to the team account
* Whether to include the document owner (sender) details when sending
emails to the recipients.
### Include Sender Details
If the Sender Details setting is enabled, the emails sent by the team
will include the sender's name:
> "Example User" on behalf of "Example Team" has invited you to sign
"document.pdf"
Otherwise, the email will say:
> "Example Team" has invited you to sign "document.pdf"
### Default Document Visibility
This new option allows users to set the default visibility for the
documents uploaded to the team account. It can have the following
values:
* Everyone
* Manager and above
* Admins only
If the default document visibility isn't set, the document will be set
to the role of the user who created the document:
* If a user with the "User" role creates a document, the document's
visibility is set to "Everyone".
* Manager role -> "Manager and above"
* Admin role -> "Admins only"
Otherwise, if there is a default document visibility value, it uses that
value.
#### Gotcha
To avoid issues, the `document owner` and the `recipient` can access the
document irrespective of their role. For example:
* If a team member with the role "Member" uploads a document and the
default document visibility is "Admins", only the document owner and
admins can access the document.
* Similar to the other scenarios.
* If an admin uploads a document and the default document visibility is
"Admins", the recipient can access the document.
* The admins have access to all the documents.
* Managers have access to documents with the visibility set to
"Everyone" and "Manager and above"
* Members have access only to the documents with the visibility set to
"Everyone".
## Testing Performed
Tested it locally.
2024-11-08 13:50:49 +02:00
|
|
|
model TeamGlobalSettings {
|
2024-11-25 06:47:26 +02:00
|
|
|
teamId Int @unique
|
|
|
|
|
documentVisibility DocumentVisibility @default(EVERYONE)
|
|
|
|
|
documentLanguage String @default("en")
|
|
|
|
|
includeSenderDetails Boolean @default(true)
|
2024-11-26 12:03:44 +02:00
|
|
|
typedSignatureEnabled Boolean @default(true)
|
2024-11-25 06:47:26 +02:00
|
|
|
includeSigningCertificate Boolean @default(true)
|
feat: add global settings for teams (#1391)
## Description
This PR introduces global settings for teams. At the moment, it allows
team admins to configure the following:
* The default visibility of the documents uploaded to the team account
* Whether to include the document owner (sender) details when sending
emails to the recipients.
### Include Sender Details
If the Sender Details setting is enabled, the emails sent by the team
will include the sender's name:
> "Example User" on behalf of "Example Team" has invited you to sign
"document.pdf"
Otherwise, the email will say:
> "Example Team" has invited you to sign "document.pdf"
### Default Document Visibility
This new option allows users to set the default visibility for the
documents uploaded to the team account. It can have the following
values:
* Everyone
* Manager and above
* Admins only
If the default document visibility isn't set, the document will be set
to the role of the user who created the document:
* If a user with the "User" role creates a document, the document's
visibility is set to "Everyone".
* Manager role -> "Manager and above"
* Admin role -> "Admins only"
Otherwise, if there is a default document visibility value, it uses that
value.
#### Gotcha
To avoid issues, the `document owner` and the `recipient` can access the
document irrespective of their role. For example:
* If a team member with the role "Member" uploads a document and the
default document visibility is "Admins", only the document owner and
admins can access the document.
* Similar to the other scenarios.
* If an admin uploads a document and the default document visibility is
"Admins", the recipient can access the document.
* The admins have access to all the documents.
* Managers have access to documents with the visibility set to
"Everyone" and "Manager and above"
* Members have access only to the documents with the visibility set to
"Everyone".
## Testing Performed
Tested it locally.
2024-11-08 13:50:49 +02:00
|
|
|
|
|
|
|
|
brandingEnabled Boolean @default(false)
|
|
|
|
|
brandingLogo String @default("")
|
|
|
|
|
brandingUrl String @default("")
|
|
|
|
|
brandingCompanyDetails String @default("")
|
|
|
|
|
brandingHidePoweredBy Boolean @default(false)
|
|
|
|
|
|
|
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-06 16:16:10 +11:00
|
|
|
model Team {
|
2024-06-27 21:50:42 +10:00
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
name String
|
|
|
|
|
url String @unique
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
avatarImageId String?
|
|
|
|
|
customerId String? @unique
|
|
|
|
|
ownerUserId Int
|
|
|
|
|
|
2024-02-06 16:16:10 +11:00
|
|
|
members TeamMember[]
|
|
|
|
|
invites TeamMemberInvite[]
|
|
|
|
|
teamEmail TeamEmail?
|
|
|
|
|
emailVerification TeamEmailVerification?
|
|
|
|
|
transferVerification TeamTransferVerification?
|
feat: add global settings for teams (#1391)
## Description
This PR introduces global settings for teams. At the moment, it allows
team admins to configure the following:
* The default visibility of the documents uploaded to the team account
* Whether to include the document owner (sender) details when sending
emails to the recipients.
### Include Sender Details
If the Sender Details setting is enabled, the emails sent by the team
will include the sender's name:
> "Example User" on behalf of "Example Team" has invited you to sign
"document.pdf"
Otherwise, the email will say:
> "Example Team" has invited you to sign "document.pdf"
### Default Document Visibility
This new option allows users to set the default visibility for the
documents uploaded to the team account. It can have the following
values:
* Everyone
* Manager and above
* Admins only
If the default document visibility isn't set, the document will be set
to the role of the user who created the document:
* If a user with the "User" role creates a document, the document's
visibility is set to "Everyone".
* Manager role -> "Manager and above"
* Admin role -> "Admins only"
Otherwise, if there is a default document visibility value, it uses that
value.
#### Gotcha
To avoid issues, the `document owner` and the `recipient` can access the
document irrespective of their role. For example:
* If a team member with the role "Member" uploads a document and the
default document visibility is "Admins", only the document owner and
admins can access the document.
* Similar to the other scenarios.
* If an admin uploads a document and the default document visibility is
"Admins", the recipient can access the document.
* The admins have access to all the documents.
* Managers have access to documents with the visibility set to
"Everyone" and "Manager and above"
* Members have access only to the documents with the visibility set to
"Everyone".
## Testing Performed
Tested it locally.
2024-11-08 13:50:49 +02:00
|
|
|
teamGlobalSettings TeamGlobalSettings?
|
2024-06-27 21:50:42 +10:00
|
|
|
avatarImage AvatarImage? @relation(fields: [avatarImageId], references: [id], onDelete: SetNull)
|
2024-02-06 16:16:10 +11:00
|
|
|
|
2024-06-06 14:46:48 +10:00
|
|
|
profile TeamProfile?
|
2024-04-24 17:32:11 +10:00
|
|
|
owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
|
2024-02-06 16:16:10 +11:00
|
|
|
subscription Subscription?
|
|
|
|
|
|
2024-02-08 12:33:20 +11:00
|
|
|
document Document[]
|
|
|
|
|
templates Template[]
|
2024-02-22 13:39:34 +11:00
|
|
|
ApiToken ApiToken[]
|
2024-02-27 13:38:12 +11:00
|
|
|
Webhook Webhook[]
|
2024-02-06 16:16:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamPending {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
name String
|
|
|
|
|
url String @unique
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
customerId String @unique
|
|
|
|
|
ownerUserId Int
|
|
|
|
|
|
|
|
|
|
owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamMember {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
teamId Int
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
role TeamMemberRole
|
|
|
|
|
userId Int
|
2024-04-24 17:32:11 +10:00
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2024-02-06 16:16:10 +11:00
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
|
|
@@unique([userId, teamId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamEmail {
|
|
|
|
|
teamId Int @id @unique
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
name String
|
|
|
|
|
email String @unique
|
|
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamEmailVerification {
|
|
|
|
|
teamId Int @id @unique
|
|
|
|
|
name String
|
|
|
|
|
email String
|
|
|
|
|
token String @unique
|
2024-08-28 14:08:35 +10:00
|
|
|
completed Boolean @default(false)
|
2024-02-06 16:16:10 +11:00
|
|
|
expiresAt DateTime
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamTransferVerification {
|
|
|
|
|
teamId Int @id @unique
|
|
|
|
|
userId Int
|
|
|
|
|
name String
|
|
|
|
|
email String
|
|
|
|
|
token String @unique
|
2024-08-28 14:08:35 +10:00
|
|
|
completed Boolean @default(false)
|
2024-02-06 16:16:10 +11:00
|
|
|
expiresAt DateTime
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
clearPaymentMethods Boolean @default(false)
|
|
|
|
|
|
|
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TeamMemberInvite {
|
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
|
teamId Int
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
email String
|
|
|
|
|
status TeamMemberInviteStatus @default(PENDING)
|
|
|
|
|
role TeamMemberRole
|
|
|
|
|
token String @unique
|
|
|
|
|
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
|
|
@@unique([teamId, email])
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-06 22:54:24 +00:00
|
|
|
enum TemplateType {
|
|
|
|
|
PUBLIC
|
|
|
|
|
PRIVATE
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-10 19:45:19 +07:00
|
|
|
model TemplateMeta {
|
2024-11-26 12:03:44 +02:00
|
|
|
id String @id @default(cuid())
|
|
|
|
|
subject String?
|
|
|
|
|
message String?
|
|
|
|
|
timezone String? @default("Etc/UTC") @db.Text
|
|
|
|
|
password String?
|
|
|
|
|
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
|
|
|
|
|
signingOrder DocumentSigningOrder? @default(PARALLEL)
|
|
|
|
|
typedSignatureEnabled Boolean @default(true)
|
|
|
|
|
distributionMethod DocumentDistributionMethod @default(EMAIL)
|
|
|
|
|
|
|
|
|
|
templateId Int @unique
|
|
|
|
|
template Template @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
|
redirectUrl String?
|
|
|
|
|
language String @default("en")
|
|
|
|
|
emailSettings Json?
|
2024-05-10 19:45:19 +07:00
|
|
|
}
|
|
|
|
|
|
2023-10-06 22:54:24 +00:00
|
|
|
model Template {
|
2024-05-10 19:45:19 +07:00
|
|
|
id Int @id @default(autoincrement())
|
2024-07-13 16:45:09 +10:00
|
|
|
externalId String?
|
2024-05-10 19:45:19 +07:00
|
|
|
type TemplateType @default(PRIVATE)
|
2023-12-15 22:07:27 +11:00
|
|
|
title String
|
|
|
|
|
userId Int
|
2024-02-08 12:33:20 +11:00
|
|
|
teamId Int?
|
2024-05-10 19:45:19 +07:00
|
|
|
authOptions Json?
|
|
|
|
|
templateMeta TemplateMeta?
|
2023-10-06 22:54:24 +00:00
|
|
|
templateDocumentDataId String
|
2024-05-10 19:45:19 +07:00
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @default(now()) @updatedAt
|
2024-06-06 14:46:48 +10:00
|
|
|
publicTitle String @default("")
|
|
|
|
|
publicDescription String @default("")
|
2023-12-15 22:07:27 +11:00
|
|
|
|
2024-06-02 15:49:09 +10:00
|
|
|
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
|
|
|
templateDocumentData DocumentData @relation(fields: [templateDocumentDataId], references: [id], onDelete: Cascade)
|
|
|
|
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2024-01-30 17:31:27 +11:00
|
|
|
Recipient Recipient[]
|
|
|
|
|
Field Field[]
|
2024-06-02 15:49:09 +10:00
|
|
|
directLink TemplateDirectLink?
|
|
|
|
|
documents Document[]
|
2023-10-06 22:54:24 +00:00
|
|
|
|
|
|
|
|
@@unique([templateDocumentDataId])
|
|
|
|
|
}
|
2024-02-22 20:13:17 +00:00
|
|
|
|
2024-06-02 15:49:09 +10:00
|
|
|
model TemplateDirectLink {
|
|
|
|
|
id String @id @unique @default(cuid())
|
|
|
|
|
templateId Int @unique
|
|
|
|
|
token String @unique
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
enabled Boolean
|
|
|
|
|
|
|
|
|
|
directTemplateRecipientId Int
|
|
|
|
|
|
|
|
|
|
template Template @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-23 10:47:01 +00:00
|
|
|
model SiteSettings {
|
|
|
|
|
id String @id
|
|
|
|
|
enabled Boolean @default(false)
|
|
|
|
|
data Json
|
|
|
|
|
lastModifiedByUserId Int?
|
|
|
|
|
lastModifiedAt DateTime @default(now())
|
2024-04-24 17:32:11 +10:00
|
|
|
lastModifiedByUser User? @relation(fields: [lastModifiedByUserId], references: [id], onDelete: SetNull)
|
2024-02-22 20:13:17 +00:00
|
|
|
}
|
2024-05-16 15:44:39 +10:00
|
|
|
|
|
|
|
|
enum BackgroundJobStatus {
|
|
|
|
|
PENDING
|
|
|
|
|
PROCESSING
|
|
|
|
|
COMPLETED
|
|
|
|
|
FAILED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model BackgroundJob {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
status BackgroundJobStatus @default(PENDING)
|
|
|
|
|
payload Json?
|
|
|
|
|
retried Int @default(0)
|
|
|
|
|
maxRetries Int @default(3)
|
|
|
|
|
|
|
|
|
|
// Taken from the job definition
|
|
|
|
|
jobId String
|
|
|
|
|
name String
|
|
|
|
|
version String
|
|
|
|
|
|
|
|
|
|
submittedAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
completedAt DateTime?
|
|
|
|
|
lastRetriedAt DateTime?
|
|
|
|
|
|
|
|
|
|
tasks BackgroundJobTask[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum BackgroundJobTaskStatus {
|
|
|
|
|
PENDING
|
|
|
|
|
COMPLETED
|
|
|
|
|
FAILED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model BackgroundJobTask {
|
|
|
|
|
id String @id
|
|
|
|
|
name String
|
|
|
|
|
status BackgroundJobTaskStatus @default(PENDING)
|
|
|
|
|
|
|
|
|
|
result Json?
|
|
|
|
|
retried Int @default(0)
|
|
|
|
|
maxRetries Int @default(3)
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
completedAt DateTime?
|
|
|
|
|
|
|
|
|
|
jobId String
|
|
|
|
|
backgroundJob BackgroundJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
|
|
|
}
|
2024-06-27 21:50:42 +10:00
|
|
|
|
|
|
|
|
model AvatarImage {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
bytes String
|
|
|
|
|
|
|
|
|
|
team Team[]
|
|
|
|
|
user User[]
|
|
|
|
|
}
|