added backup and email client

This commit is contained in:
2026-02-01 00:02:35 +01:00
parent ef18381dd8
commit 8c9e61cf17
210 changed files with 24211 additions and 742 deletions
+53 -4
View File
File diff suppressed because one or more lines are too long
+50
View File
@@ -137,6 +137,7 @@ exports.Prisma.UserScalarFieldEnum = {
firstName: 'firstName',
lastName: 'lastName',
isActive: 'isActive',
tokenInvalidatedAt: 'tokenInvalidatedAt',
customerId: 'customerId',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
@@ -259,6 +260,13 @@ exports.Prisma.EmailProviderConfigScalarFieldEnum = {
passwordEncrypted: 'passwordEncrypted',
domain: 'domain',
defaultForwardEmail: 'defaultForwardEmail',
imapServer: 'imapServer',
imapPort: 'imapPort',
smtpServer: 'smtpServer',
smtpPort: 'smtpPort',
imapEncryption: 'imapEncryption',
smtpEncryption: 'smtpEncryption',
allowSelfSignedCerts: 'allowSelfSignedCerts',
isActive: 'isActive',
isDefault: 'isDefault',
createdAt: 'createdAt',
@@ -275,6 +283,36 @@ exports.Prisma.StressfreiEmailScalarFieldEnum = {
isProvisioned: 'isProvisioned',
provisionedAt: 'provisionedAt',
provisionError: 'provisionError',
hasMailbox: 'hasMailbox',
emailPasswordEncrypted: 'emailPasswordEncrypted',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.CachedEmailScalarFieldEnum = {
id: 'id',
stressfreiEmailId: 'stressfreiEmailId',
folder: 'folder',
messageId: 'messageId',
uid: 'uid',
subject: 'subject',
fromAddress: 'fromAddress',
fromName: 'fromName',
toAddresses: 'toAddresses',
ccAddresses: 'ccAddresses',
receivedAt: 'receivedAt',
textBody: 'textBody',
htmlBody: 'htmlBody',
hasAttachments: 'hasAttachments',
attachmentNames: 'attachmentNames',
contractId: 'contractId',
assignedAt: 'assignedAt',
assignedBy: 'assignedBy',
isAutoAssigned: 'isAutoAssigned',
isRead: 'isRead',
isStarred: 'isStarred',
isDeleted: 'isDeleted',
deletedAt: 'deletedAt',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
@@ -542,6 +580,17 @@ exports.EmailProviderType = exports.$Enums.EmailProviderType = {
DIRECTADMIN: 'DIRECTADMIN'
};
exports.MailEncryption = exports.$Enums.MailEncryption = {
SSL: 'SSL',
STARTTLS: 'STARTTLS',
NONE: 'NONE'
};
exports.EmailFolder = exports.$Enums.EmailFolder = {
INBOX: 'INBOX',
SENT: 'SENT'
};
exports.MeterType = exports.$Enums.MeterType = {
ELECTRICITY: 'ELECTRICITY',
GAS: 'GAS'
@@ -592,6 +641,7 @@ exports.Prisma.ModelName = {
IdentityDocument: 'IdentityDocument',
EmailProviderConfig: 'EmailProviderConfig',
StressfreiEmail: 'StressfreiEmail',
CachedEmail: 'CachedEmail',
Meter: 'Meter',
MeterReading: 'MeterReading',
SalesPlatform: 'SalesPlatform',
+3210 -60
View File
File diff suppressed because it is too large Load Diff
+53 -4
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "prisma-client-f3be941c86c0d933a2a09d69aafc49ad121411869df4ce4f365fdf53679b90db",
"name": "prisma-client-3c4bb688688ba372393d0bf86523c07e8b4de3ff0d9ad23a89f905f15047a1a5",
"main": "index.js",
"types": "index.d.ts",
"browser": "index-browser.js",
+109 -25
View File
@@ -20,17 +20,18 @@ model AppSetting {
// ==================== USERS & AUTH ====================
model User {
id Int @id @default(autoincrement())
email String @unique
password String
firstName String
lastName String
isActive Boolean @default(true)
customerId Int? @unique
customer Customer? @relation(fields: [customerId], references: [id])
roles UserRole[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id Int @id @default(autoincrement())
email String @unique
password String
firstName String
lastName String
isActive Boolean @default(true)
tokenInvalidatedAt DateTime? // Zeitpunkt ab dem alle Tokens ungültig sind (für Zwangslogout bei Rechteänderung)
customerId Int? @unique
customer Customer? @relation(fields: [customerId], references: [id])
roles UserRole[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Role {
@@ -216,6 +217,13 @@ enum EmailProviderType {
DIRECTADMIN
}
// Verschlüsselungstyp für E-Mail-Verbindungen
enum MailEncryption {
SSL // Implicit SSL/TLS (Ports 465/993) - Verschlüsselung von Anfang an
STARTTLS // STARTTLS (Ports 587/143) - Startet unverschlüsselt, dann Upgrade
NONE // Keine Verschlüsselung (Ports 25/143)
}
model EmailProviderConfig {
id Int @id @default(autoincrement())
name String @unique // z.B. "Plesk Hauptserver"
@@ -226,28 +234,103 @@ model EmailProviderConfig {
passwordEncrypted String? // Passwort (verschlüsselt)
domain String // Domain für E-Mails (z.B. stressfrei-wechseln.de)
defaultForwardEmail String? // Standard-Weiterleitungsadresse (unsere eigene)
isActive Boolean @default(true)
isDefault Boolean @default(false) // Standard-Provider
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// IMAP/SMTP-Server für E-Mail-Client (optional, default: mail.{domain})
imapServer String? // z.B. "mail.stressfrei-wechseln.de"
imapPort Int? @default(993)
smtpServer String?
smtpPort Int? @default(465)
// Verschlüsselungs-Einstellungen
imapEncryption MailEncryption @default(SSL) // SSL, STARTTLS oder NONE
smtpEncryption MailEncryption @default(SSL) // SSL, STARTTLS oder NONE
allowSelfSignedCerts Boolean @default(false) // Selbstsignierte Zertifikate erlauben
isActive Boolean @default(true)
isDefault Boolean @default(false) // Standard-Provider
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ==================== STRESSFREI-WECHSELN EMAIL ADDRESSES ====================
model StressfreiEmail {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
customerId Int
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
email String // Die Weiterleitungs-E-Mail-Adresse
platform String? // Für welche Plattform (z.B. "Freenet", "Klarmobil")
notes String? @db.Text // Optionale Notizen
isActive Boolean @default(true)
isProvisioned Boolean @default(false) // Wurde bei Provider angelegt?
notes String? @db.Text // Optionale Notizen
isActive Boolean @default(true)
isProvisioned Boolean @default(false) // Wurde bei Provider angelegt?
provisionedAt DateTime? // Wann wurde provisioniert?
provisionError String? @db.Text // Fehlermeldung falls Provisionierung fehlschlug
contracts Contract[] // Verträge die diese E-Mail als Benutzername verwenden
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
provisionError String? @db.Text // Fehlermeldung falls Provisionierung fehlschlug
// Mailbox-Zugangsdaten (für IMAP/SMTP-Zugang)
hasMailbox Boolean @default(false) // Hat echte Mailbox (nicht nur Weiterleitung)?
emailPasswordEncrypted String? // Verschlüsseltes Mailbox-Passwort (AES-256-GCM)
contracts Contract[] // Verträge die diese E-Mail als Benutzername verwenden
cachedEmails CachedEmail[] // Gecachte E-Mails aus dieser Mailbox
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ==================== CACHED EMAILS (E-Mail-Client) ====================
enum EmailFolder {
INBOX
SENT
}
model CachedEmail {
id Int @id @default(autoincrement())
stressfreiEmailId Int
stressfreiEmail StressfreiEmail @relation(fields: [stressfreiEmailId], references: [id], onDelete: Cascade)
// Ordner (Posteingang oder Gesendet)
folder EmailFolder @default(INBOX)
// IMAP-Identifikation
messageId String // RFC 5322 Message-ID
uid Int // IMAP UID (für Synchronisierung, bei SENT = 0)
// E-Mail-Metadaten
subject String?
fromAddress String
fromName String?
toAddresses String @db.Text // JSON Array
ccAddresses String? @db.Text // JSON Array
receivedAt DateTime
// Inhalt
textBody String? @db.LongText
htmlBody String? @db.LongText
hasAttachments Boolean @default(false)
attachmentNames String? @db.Text // JSON Array
// Vertragszuordnung
contractId Int?
contract Contract? @relation(fields: [contractId], references: [id], onDelete: SetNull)
assignedAt DateTime?
assignedBy Int? // User ID der die Zuordnung gemacht hat
isAutoAssigned Boolean @default(false) // true = automatisch beim Senden aus Vertrag
// Flags
isRead Boolean @default(false)
isStarred Boolean @default(false)
// Papierkorb
isDeleted Boolean @default(false) // Im Papierkorb?
deletedAt DateTime? // Wann gelöscht?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([stressfreiEmailId, messageId, folder]) // Folder hinzugefügt: gleiche MessageID kann in INBOX und SENT existieren
@@index([contractId])
@@index([stressfreiEmailId, folder, receivedAt])
@@index([stressfreiEmailId, isDeleted]) // Für Papierkorb-Abfragen
}
// ==================== METERS (Energy) ====================
@@ -464,7 +547,8 @@ model Contract {
tvDetails TvContractDetails?
carInsuranceDetails CarInsuranceDetails?
tasks ContractTask[]
tasks ContractTask[]
assignedEmails CachedEmail[] // Zugeordnete E-Mails aus dem E-Mail-Client
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
+50
View File
@@ -137,6 +137,7 @@ exports.Prisma.UserScalarFieldEnum = {
firstName: 'firstName',
lastName: 'lastName',
isActive: 'isActive',
tokenInvalidatedAt: 'tokenInvalidatedAt',
customerId: 'customerId',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
@@ -259,6 +260,13 @@ exports.Prisma.EmailProviderConfigScalarFieldEnum = {
passwordEncrypted: 'passwordEncrypted',
domain: 'domain',
defaultForwardEmail: 'defaultForwardEmail',
imapServer: 'imapServer',
imapPort: 'imapPort',
smtpServer: 'smtpServer',
smtpPort: 'smtpPort',
imapEncryption: 'imapEncryption',
smtpEncryption: 'smtpEncryption',
allowSelfSignedCerts: 'allowSelfSignedCerts',
isActive: 'isActive',
isDefault: 'isDefault',
createdAt: 'createdAt',
@@ -275,6 +283,36 @@ exports.Prisma.StressfreiEmailScalarFieldEnum = {
isProvisioned: 'isProvisioned',
provisionedAt: 'provisionedAt',
provisionError: 'provisionError',
hasMailbox: 'hasMailbox',
emailPasswordEncrypted: 'emailPasswordEncrypted',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.CachedEmailScalarFieldEnum = {
id: 'id',
stressfreiEmailId: 'stressfreiEmailId',
folder: 'folder',
messageId: 'messageId',
uid: 'uid',
subject: 'subject',
fromAddress: 'fromAddress',
fromName: 'fromName',
toAddresses: 'toAddresses',
ccAddresses: 'ccAddresses',
receivedAt: 'receivedAt',
textBody: 'textBody',
htmlBody: 'htmlBody',
hasAttachments: 'hasAttachments',
attachmentNames: 'attachmentNames',
contractId: 'contractId',
assignedAt: 'assignedAt',
assignedBy: 'assignedBy',
isAutoAssigned: 'isAutoAssigned',
isRead: 'isRead',
isStarred: 'isStarred',
isDeleted: 'isDeleted',
deletedAt: 'deletedAt',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
@@ -542,6 +580,17 @@ exports.EmailProviderType = exports.$Enums.EmailProviderType = {
DIRECTADMIN: 'DIRECTADMIN'
};
exports.MailEncryption = exports.$Enums.MailEncryption = {
SSL: 'SSL',
STARTTLS: 'STARTTLS',
NONE: 'NONE'
};
exports.EmailFolder = exports.$Enums.EmailFolder = {
INBOX: 'INBOX',
SENT: 'SENT'
};
exports.MeterType = exports.$Enums.MeterType = {
ELECTRICITY: 'ELECTRICITY',
GAS: 'GAS'
@@ -592,6 +641,7 @@ exports.Prisma.ModelName = {
IdentityDocument: 'IdentityDocument',
EmailProviderConfig: 'EmailProviderConfig',
StressfreiEmail: 'StressfreiEmail',
CachedEmail: 'CachedEmail',
Meter: 'Meter',
MeterReading: 'MeterReading',
SalesPlatform: 'SalesPlatform',