Quest Domain Complete (F-004): - quest_account_request: new user registration requests - quest_notification + alert reads: notification/alert system - quest_email_event + subscriptions: email event management - quest_email_log: email tracking - quest_plant + inventory_type + inventory_plant: plant/inventory configuration - quest_processed_order_acknowledgement_email: duplicate prevention Remaining Domains Complete (F-005): Shipment Requests: - ship_request + ship_request_detail: shipment request cart workflow Allocation Requests: - alloc_request + alloc_request_detail + alloc_plant: coil allocation workflow Invoice Management: - inv_upload + inv_upload_entry + inv_upload_status: invoice upload/processing Finance/AP: - finance_ap_check_processing_batch + status: AP check processing Paint Schedule: - paint_plant + paint_line + paint_line_type + paint_plant_line + paint_schedule Documentation: - doc_category + doc_article + doc_article_permission_group: knowledge base Wave/EDI: - wave_process + wave_process_history: EDI processing Task Scheduler: - lts_task + lts_task_type + lts_task_schedule + lts_task_execution Total: 60+ tables, 600+ columns across all domains. All migrations applied successfully. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1000 lines
32 KiB
Text
1000 lines
32 KiB
Text
// Prisma schema for Vorteq Quest Portal
|
|
// PostgreSQL 16 database
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// =============================================================================
|
|
// AUTH DOMAIN - User Authentication & Authorization
|
|
// =============================================================================
|
|
|
|
// Core user authentication table (Better Auth compatible)
|
|
model auth_user {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
email_verified Boolean @default(false)
|
|
name String?
|
|
image String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
// Password authentication
|
|
password_hash String?
|
|
|
|
// Account security
|
|
deactivated Boolean @default(false)
|
|
deactivated_at DateTime?
|
|
deactivation_reason String?
|
|
|
|
// Login tracking
|
|
login_count Int @default(0)
|
|
failed_login_count Int @default(0)
|
|
last_login_at DateTime?
|
|
last_login_ip String?
|
|
last_failed_login_at DateTime?
|
|
|
|
// Two-factor authentication
|
|
two_factor_enabled Boolean @default(false)
|
|
two_factor_secret String?
|
|
two_factor_backup_codes String?
|
|
|
|
// SSO fields
|
|
sso_provider String?
|
|
sso_id String?
|
|
|
|
// Relationships
|
|
auth_user_type_id String
|
|
auth_user_type auth_user_type @relation(fields: [auth_user_type_id], references: [id])
|
|
auth_domain_id String?
|
|
auth_domain auth_domain? @relation(fields: [auth_domain_id], references: [id])
|
|
|
|
sessions auth_session[]
|
|
accounts auth_account[]
|
|
password_history auth_password_history[]
|
|
password_resets auth_password_reset[]
|
|
security_answers auth_security_answer[]
|
|
quest_user quest_user?
|
|
|
|
@@index([email])
|
|
@@index([auth_user_type_id])
|
|
@@index([auth_domain_id])
|
|
@@map("auth_user")
|
|
}
|
|
|
|
// User session table (Better Auth compatible)
|
|
model auth_session {
|
|
id String @id @default(cuid())
|
|
user_id String
|
|
token String @unique
|
|
expires_at DateTime
|
|
ip_address String?
|
|
user_agent String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
user auth_user @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([user_id])
|
|
@@index([token])
|
|
@@index([expires_at])
|
|
@@map("auth_session")
|
|
}
|
|
|
|
// OAuth/Social provider accounts (Better Auth compatible)
|
|
model auth_account {
|
|
id String @id @default(cuid())
|
|
user_id String
|
|
account_id String
|
|
provider_id String
|
|
access_token String?
|
|
refresh_token String?
|
|
id_token String?
|
|
access_token_expires_at DateTime?
|
|
refresh_token_expires_at DateTime?
|
|
scope String?
|
|
password String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
user auth_user @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([provider_id, account_id])
|
|
@@index([user_id])
|
|
@@map("auth_account")
|
|
}
|
|
|
|
// OAuth client configuration
|
|
model auth_oauth_client {
|
|
id String @id @default(cuid())
|
|
client_id String @unique
|
|
client_secret String
|
|
redirect_uris String[] // Array of allowed redirect URIs
|
|
grant_types String[] // Array of allowed grant types
|
|
name String
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
revoked Boolean @default(false)
|
|
|
|
access_tokens auth_oauth_access_token[]
|
|
refresh_tokens auth_oauth_refresh_token[]
|
|
|
|
@@map("auth_oauth_client")
|
|
}
|
|
|
|
// OAuth access tokens
|
|
model auth_oauth_access_token {
|
|
id String @id @default(cuid())
|
|
access_token String @unique
|
|
client_id String
|
|
user_id String?
|
|
expires_at DateTime
|
|
scopes String[] // Array of scopes
|
|
created_at DateTime @default(now())
|
|
|
|
client auth_oauth_client @relation(fields: [client_id], references: [client_id], onDelete: Cascade)
|
|
|
|
@@index([access_token])
|
|
@@index([expires_at])
|
|
@@map("auth_oauth_access_token")
|
|
}
|
|
|
|
// OAuth refresh tokens
|
|
model auth_oauth_refresh_token {
|
|
id String @id @default(cuid())
|
|
refresh_token String @unique
|
|
access_token_id String?
|
|
client_id String
|
|
user_id String?
|
|
expires_at DateTime
|
|
scopes String[] // Array of scopes
|
|
created_at DateTime @default(now())
|
|
revoked Boolean @default(false)
|
|
|
|
client auth_oauth_client @relation(fields: [client_id], references: [client_id], onDelete: Cascade)
|
|
|
|
@@index([refresh_token])
|
|
@@index([expires_at])
|
|
@@map("auth_oauth_refresh_token")
|
|
}
|
|
|
|
// User type/role definitions
|
|
model auth_user_type {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
is_admin Boolean @default(false)
|
|
is_customer Boolean @default(false)
|
|
is_internal Boolean @default(false)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
users auth_user[]
|
|
|
|
@@map("auth_user_type")
|
|
}
|
|
|
|
// Domain/company grouping for multi-tenant scenarios
|
|
model auth_domain {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
users auth_user[]
|
|
|
|
@@map("auth_domain")
|
|
}
|
|
|
|
// Password history for preventing reuse
|
|
model auth_password_history {
|
|
id String @id @default(cuid())
|
|
user_id String
|
|
password_hash String
|
|
created_at DateTime @default(now())
|
|
|
|
user auth_user @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([user_id])
|
|
@@map("auth_password_history")
|
|
}
|
|
|
|
// Password reset tokens
|
|
model auth_password_reset {
|
|
id String @id @default(cuid())
|
|
user_id String
|
|
token String @unique
|
|
expires_at DateTime
|
|
used_at DateTime?
|
|
ip_address String?
|
|
min_time_bypass Boolean @default(false)
|
|
created_at DateTime @default(now())
|
|
|
|
user auth_user @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([token])
|
|
@@index([user_id])
|
|
@@index([expires_at])
|
|
@@map("auth_password_reset")
|
|
}
|
|
|
|
// Permission groups (roles)
|
|
model auth_permission_group {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
rules auth_permission_group_rule[]
|
|
|
|
@@map("auth_permission_group")
|
|
}
|
|
|
|
// Permission rules (individual permissions)
|
|
model auth_permission_rule {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
auth_permission_rule_category_id String?
|
|
category auth_permission_rule_category? @relation(fields: [auth_permission_rule_category_id], references: [id])
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
groups auth_permission_group_rule[]
|
|
|
|
@@index([auth_permission_rule_category_id])
|
|
@@map("auth_permission_rule")
|
|
}
|
|
|
|
// Permission rule categories for organization
|
|
model auth_permission_rule_category {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
rules auth_permission_rule[]
|
|
|
|
@@map("auth_permission_rule_category")
|
|
}
|
|
|
|
// Junction table: permission groups to rules (many-to-many)
|
|
model auth_permission_group_rule {
|
|
id String @id @default(cuid())
|
|
auth_permission_group_id String
|
|
auth_permission_rule_id String
|
|
created_at DateTime @default(now())
|
|
|
|
group auth_permission_group @relation(fields: [auth_permission_group_id], references: [id], onDelete: Cascade)
|
|
rule auth_permission_rule @relation(fields: [auth_permission_rule_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([auth_permission_group_id, auth_permission_rule_id])
|
|
@@index([auth_permission_group_id])
|
|
@@index([auth_permission_rule_id])
|
|
@@map("auth_permission_group_rule")
|
|
}
|
|
|
|
// Security questions for account recovery
|
|
model auth_security_question {
|
|
id String @id @default(cuid())
|
|
question String @unique
|
|
is_active Boolean @default(true)
|
|
sort_order Int @default(0)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
answers auth_security_answer[]
|
|
|
|
@@map("auth_security_question")
|
|
}
|
|
|
|
// User security question answers
|
|
model auth_security_answer {
|
|
id String @id @default(cuid())
|
|
user_id String
|
|
auth_security_question_id String
|
|
answer_hash String
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
user auth_user @relation(fields: [user_id], references: [id], onDelete: Cascade)
|
|
question auth_security_question @relation(fields: [auth_security_question_id], references: [id])
|
|
|
|
@@unique([user_id, auth_security_question_id])
|
|
@@index([user_id])
|
|
@@map("auth_security_answer")
|
|
}
|
|
|
|
// =============================================================================
|
|
// QUEST DOMAIN - Portal-specific user and company data
|
|
// =============================================================================
|
|
|
|
// Quest-specific user data (extends auth_user)
|
|
model quest_user {
|
|
id String @id @default(cuid())
|
|
auth_user_id String @unique
|
|
is_sub_user Boolean @default(false)
|
|
api_token String? @unique
|
|
api_token_expires_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
auth_user auth_user @relation(fields: [auth_user_id], references: [id], onDelete: Cascade)
|
|
companies quest_user_company[]
|
|
|
|
@@index([auth_user_id])
|
|
@@map("quest_user")
|
|
}
|
|
|
|
// Company/customer information
|
|
model quest_company {
|
|
id String @id @default(cuid())
|
|
epicor_cust_id String @unique
|
|
display_name String
|
|
can_access_invoices Boolean @default(false)
|
|
invoicing_email String?
|
|
order_ack_email String?
|
|
receives_so_emails Boolean @default(false)
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
users quest_user_company[]
|
|
|
|
@@index([epicor_cust_id])
|
|
@@map("quest_company")
|
|
}
|
|
|
|
// Junction table: users to companies (many-to-many with active company tracking)
|
|
model quest_user_company {
|
|
id String @id @default(cuid())
|
|
quest_user_id String
|
|
quest_company_id String
|
|
is_active_company Boolean @default(false)
|
|
created_at DateTime @default(now())
|
|
|
|
user quest_user @relation(fields: [quest_user_id], references: [id], onDelete: Cascade)
|
|
company quest_company @relation(fields: [quest_company_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([quest_user_id, quest_company_id])
|
|
@@index([quest_user_id])
|
|
@@index([quest_company_id])
|
|
@@map("quest_user_company")
|
|
}
|
|
|
|
// Account request for new user registration
|
|
model quest_account_request {
|
|
id String @id @default(cuid())
|
|
first_name String
|
|
last_name String
|
|
email String
|
|
phone String?
|
|
company_name String
|
|
epicor_cust_id String?
|
|
message String?
|
|
request_processed Boolean @default(false)
|
|
processed_at DateTime?
|
|
processed_by String?
|
|
approved Boolean @default(false)
|
|
rejection_reason String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
@@index([email])
|
|
@@index([request_processed])
|
|
@@map("quest_account_request")
|
|
}
|
|
|
|
// Notification/alert system
|
|
model quest_notification {
|
|
id String @id @default(cuid())
|
|
title String
|
|
text String
|
|
is_alert Boolean @default(false)
|
|
display_date DateTime
|
|
display_time String?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
alert_reads quest_user_notification_alert_read[]
|
|
|
|
@@index([is_alert])
|
|
@@index([display_date])
|
|
@@index([is_active])
|
|
@@map("quest_notification")
|
|
}
|
|
|
|
// Tracking which users have read alert notifications
|
|
model quest_user_notification_alert_read {
|
|
id String @id @default(cuid())
|
|
quest_notification_id String
|
|
auth_user_id String
|
|
read_at DateTime @default(now())
|
|
|
|
notification quest_notification @relation(fields: [quest_notification_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([quest_notification_id, auth_user_id])
|
|
@@index([auth_user_id])
|
|
@@map("quest_user_notification_alert_read")
|
|
}
|
|
|
|
// Email event definitions (types of emails that can be sent)
|
|
model quest_email_event {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
user_subscriptions quest_user_email_event[]
|
|
|
|
@@map("quest_email_event")
|
|
}
|
|
|
|
// User subscriptions to email events (many-to-many)
|
|
model quest_user_email_event {
|
|
id String @id @default(cuid())
|
|
auth_user_id String
|
|
quest_email_event_id String
|
|
subscribed Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
|
|
email_event quest_email_event @relation(fields: [quest_email_event_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([auth_user_id, quest_email_event_id])
|
|
@@index([auth_user_id])
|
|
@@map("quest_user_email_event")
|
|
}
|
|
|
|
// Email log for tracking sent emails
|
|
model quest_email_log {
|
|
id String @id @default(cuid())
|
|
to_addresses String[] // Array of recipient emails
|
|
from_address String
|
|
subject String
|
|
body String
|
|
sent_at DateTime @default(now())
|
|
status String @default("sent") // sent, failed, pending
|
|
error_message String?
|
|
quest_email_event_id String?
|
|
auth_user_id String?
|
|
|
|
@@index([sent_at])
|
|
@@index([status])
|
|
@@index([auth_user_id])
|
|
@@map("quest_email_log")
|
|
}
|
|
|
|
// Plant/facility definitions
|
|
model quest_plant {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
code String @unique
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
inventory_assignments quest_inventory_plant[]
|
|
|
|
@@map("quest_plant")
|
|
}
|
|
|
|
// Inventory type definitions (WIP, Finished Goods, etc.)
|
|
model quest_inventory_type {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
code String @unique
|
|
description String?
|
|
is_active Boolean @default(true)
|
|
sort_order Int @default(0)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
plant_assignments quest_inventory_plant[]
|
|
|
|
@@map("quest_inventory_type")
|
|
}
|
|
|
|
// Junction: which inventory types are available at which plants
|
|
model quest_inventory_plant {
|
|
id String @id @default(cuid())
|
|
quest_plant_id String
|
|
quest_inventory_type_id String
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
|
|
plant quest_plant @relation(fields: [quest_plant_id], references: [id], onDelete: Cascade)
|
|
inventory_type quest_inventory_type @relation(fields: [quest_inventory_type_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([quest_plant_id, quest_inventory_type_id])
|
|
@@index([quest_plant_id])
|
|
@@index([quest_inventory_type_id])
|
|
@@map("quest_inventory_plant")
|
|
}
|
|
|
|
// Tracking processed order acknowledgement emails to prevent duplicates
|
|
model quest_processed_order_acknowledgement_email {
|
|
id String @id @default(cuid())
|
|
epicor_order_num Int
|
|
epicor_cust_id String
|
|
epicor_po_num String?
|
|
sent_at DateTime @default(now())
|
|
quest_company_id String?
|
|
|
|
@@unique([epicor_order_num, epicor_cust_id])
|
|
@@index([epicor_cust_id])
|
|
@@index([sent_at])
|
|
@@map("quest_processed_order_acknowledgement_email")
|
|
}
|
|
|
|
// =============================================================================
|
|
// SHIPMENT REQUEST DOMAIN
|
|
// =============================================================================
|
|
|
|
// Shipment request header
|
|
model ship_request {
|
|
id String @id @default(cuid())
|
|
auth_user_id String
|
|
quest_company_id String
|
|
ship_to_address String
|
|
order_number String?
|
|
po_number String?
|
|
release_number String?
|
|
pickup_date DateTime?
|
|
instructions String?
|
|
email_recipients String[] // Array of email addresses
|
|
is_submitted Boolean @default(false)
|
|
submitted_at DateTime?
|
|
is_cancelled Boolean @default(false)
|
|
cancelled_at DateTime?
|
|
cancelled_by String?
|
|
last_cart_activity DateTime @default(now())
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
details ship_request_detail[]
|
|
|
|
@@index([auth_user_id])
|
|
@@index([quest_company_id])
|
|
@@index([is_submitted])
|
|
@@index([is_cancelled])
|
|
@@map("ship_request")
|
|
}
|
|
|
|
// Shipment request line items
|
|
model ship_request_detail {
|
|
id String @id @default(cuid())
|
|
ship_request_id String
|
|
part_num String
|
|
lot_num String?
|
|
plant String
|
|
warehouse String?
|
|
quantity Float
|
|
notes String?
|
|
created_at DateTime @default(now())
|
|
|
|
request ship_request @relation(fields: [ship_request_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([ship_request_id])
|
|
@@map("ship_request_detail")
|
|
}
|
|
|
|
// =============================================================================
|
|
// ALLOCATION REQUEST DOMAIN
|
|
// =============================================================================
|
|
|
|
// Coil allocation request header
|
|
model alloc_request {
|
|
id String @id @default(cuid())
|
|
auth_user_id String
|
|
quest_company_id String
|
|
job_number String
|
|
ship_to_address String
|
|
order_number String?
|
|
po_number String?
|
|
release_number String?
|
|
pickup_date DateTime?
|
|
instructions String?
|
|
email_recipients String[] // Array of email addresses
|
|
is_submitted Boolean @default(false)
|
|
submitted_at DateTime?
|
|
is_cancelled Boolean @default(false)
|
|
cancelled_at DateTime?
|
|
cancelled_by String?
|
|
last_cart_activity DateTime @default(now())
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
details alloc_request_detail[]
|
|
|
|
@@index([auth_user_id])
|
|
@@index([quest_company_id])
|
|
@@index([job_number])
|
|
@@index([is_submitted])
|
|
@@map("alloc_request")
|
|
}
|
|
|
|
// Allocation request line items
|
|
model alloc_request_detail {
|
|
id String @id @default(cuid())
|
|
alloc_request_id String
|
|
part_num String
|
|
lot_num String?
|
|
coil_number String?
|
|
quantity Float
|
|
notes String?
|
|
created_at DateTime @default(now())
|
|
|
|
request alloc_request @relation(fields: [alloc_request_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([alloc_request_id])
|
|
@@map("alloc_request_detail")
|
|
}
|
|
|
|
// Allocation plant assignments (which plants can allocate)
|
|
model alloc_plant {
|
|
id String @id @default(cuid())
|
|
plant_code String @unique
|
|
plant_name String
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
@@map("alloc_plant")
|
|
}
|
|
|
|
// =============================================================================
|
|
// INVOICE UPLOAD DOMAIN
|
|
// =============================================================================
|
|
|
|
// Invoice upload batch status
|
|
model inv_upload_status {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
sort_order Int @default(0)
|
|
|
|
uploads inv_upload[]
|
|
|
|
@@map("inv_upload_status")
|
|
}
|
|
|
|
// Invoice upload batch
|
|
model inv_upload {
|
|
id String @id @default(cuid())
|
|
auth_user_id String
|
|
original_filename String
|
|
storage_filename String
|
|
file_path String
|
|
file_size Int
|
|
total_pages Int?
|
|
inv_upload_status_id String
|
|
upload_notes String?
|
|
created_at DateTime @default(now())
|
|
processed_at DateTime?
|
|
|
|
status inv_upload_status @relation(fields: [inv_upload_status_id], references: [id])
|
|
entries inv_upload_entry[]
|
|
|
|
@@index([auth_user_id])
|
|
@@index([inv_upload_status_id])
|
|
@@index([created_at])
|
|
@@map("inv_upload")
|
|
}
|
|
|
|
// Individual invoice entries from upload
|
|
model inv_upload_entry {
|
|
id String @id @default(cuid())
|
|
inv_upload_id String
|
|
invoice_number String
|
|
epicor_cust_id String?
|
|
quest_company_id String?
|
|
job_number String?
|
|
page_number Int?
|
|
storage_filename String?
|
|
file_path String?
|
|
is_ignored Boolean @default(false)
|
|
is_replaced Boolean @default(false)
|
|
send_error String?
|
|
created_at DateTime @default(now())
|
|
sent_at DateTime?
|
|
|
|
upload inv_upload @relation(fields: [inv_upload_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([inv_upload_id])
|
|
@@index([invoice_number])
|
|
@@index([epicor_cust_id])
|
|
@@index([quest_company_id])
|
|
@@map("inv_upload_entry")
|
|
}
|
|
|
|
// =============================================================================
|
|
// FINANCE/AP CHECK PROCESSING DOMAIN
|
|
// =============================================================================
|
|
|
|
// AP check processing status definitions
|
|
model finance_ap_check_processing_status {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
sort_order Int @default(0)
|
|
|
|
batches finance_ap_check_processing_batch[]
|
|
|
|
@@map("finance_ap_check_processing_status")
|
|
}
|
|
|
|
// AP check processing batch tracking
|
|
model finance_ap_check_processing_batch {
|
|
id String @id @default(cuid())
|
|
auth_user_id String
|
|
group_id String
|
|
original_filename String
|
|
generated_csv_filename String?
|
|
generated_csv_path String?
|
|
finance_ap_check_processing_status_id String
|
|
error_message String?
|
|
record_count Int @default(0)
|
|
created_at DateTime @default(now())
|
|
processed_at DateTime?
|
|
|
|
status finance_ap_check_processing_status @relation(fields: [finance_ap_check_processing_status_id], references: [id])
|
|
|
|
@@index([auth_user_id])
|
|
@@index([group_id])
|
|
@@index([finance_ap_check_processing_status_id])
|
|
@@map("finance_ap_check_processing_batch")
|
|
}
|
|
|
|
// =============================================================================
|
|
// PAINT SCHEDULE DOMAIN
|
|
// =============================================================================
|
|
|
|
// Paint line types
|
|
model paint_line_type {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
|
|
lines paint_line[]
|
|
|
|
@@map("paint_line_type")
|
|
}
|
|
|
|
// Paint plants
|
|
model paint_plant {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
code String @unique
|
|
is_active Boolean @default(true)
|
|
|
|
plant_lines paint_plant_line[]
|
|
|
|
@@map("paint_plant")
|
|
}
|
|
|
|
// Paint lines
|
|
model paint_line {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
paint_line_type_id String
|
|
is_active Boolean @default(true)
|
|
|
|
line_type paint_line_type @relation(fields: [paint_line_type_id], references: [id])
|
|
plant_lines paint_plant_line[]
|
|
schedules paint_schedule[]
|
|
|
|
@@map("paint_line")
|
|
}
|
|
|
|
// Junction: which lines are at which plants
|
|
model paint_plant_line {
|
|
id String @id @default(cuid())
|
|
paint_plant_id String
|
|
paint_line_id String
|
|
is_active Boolean @default(true)
|
|
|
|
plant paint_plant @relation(fields: [paint_plant_id], references: [id], onDelete: Cascade)
|
|
line paint_line @relation(fields: [paint_line_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([paint_plant_id, paint_line_id])
|
|
@@map("paint_plant_line")
|
|
}
|
|
|
|
// Paint schedule entries
|
|
model paint_schedule {
|
|
id String @id @default(cuid())
|
|
paint_line_id String
|
|
job_id String?
|
|
part_description String?
|
|
customer String?
|
|
quantity Int?
|
|
estimated_run_time Float?
|
|
start_time DateTime?
|
|
notes String?
|
|
is_complete Boolean @default(false)
|
|
line_speed Float?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
line paint_line @relation(fields: [paint_line_id], references: [id])
|
|
|
|
@@index([paint_line_id])
|
|
@@index([start_time])
|
|
@@index([is_complete])
|
|
@@map("paint_schedule")
|
|
}
|
|
|
|
// =============================================================================
|
|
// DOCUMENTATION/KNOWLEDGE BASE DOMAIN
|
|
// =============================================================================
|
|
|
|
// Documentation categories
|
|
model doc_category {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
icon String?
|
|
sort_order Int @default(0)
|
|
is_active Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
articles doc_article[]
|
|
|
|
@@map("doc_category")
|
|
}
|
|
|
|
// Documentation articles
|
|
model doc_article {
|
|
id String @id @default(cuid())
|
|
title String
|
|
content String
|
|
doc_category_id String
|
|
is_published Boolean @default(false)
|
|
sort_order Int @default(0)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
created_by String?
|
|
updated_by String?
|
|
|
|
category doc_category @relation(fields: [doc_category_id], references: [id])
|
|
permission_groups doc_article_permission_group[]
|
|
|
|
@@index([doc_category_id])
|
|
@@index([is_published])
|
|
@@map("doc_article")
|
|
}
|
|
|
|
// Junction: which permission groups can see which articles
|
|
model doc_article_permission_group {
|
|
id String @id @default(cuid())
|
|
doc_article_id String
|
|
auth_permission_group_id String
|
|
created_at DateTime @default(now())
|
|
|
|
article doc_article @relation(fields: [doc_article_id], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([doc_article_id, auth_permission_group_id])
|
|
@@map("doc_article_permission_group")
|
|
}
|
|
|
|
// =============================================================================
|
|
// WAVE/EDI PROCESSING DOMAIN
|
|
// =============================================================================
|
|
|
|
// Wave process definitions
|
|
model wave_process {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
is_enabled Boolean @default(true)
|
|
schedule_cron String?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
history wave_process_history[]
|
|
|
|
@@map("wave_process")
|
|
}
|
|
|
|
// Wave process execution history
|
|
model wave_process_history {
|
|
id String @id @default(cuid())
|
|
wave_process_id String
|
|
started_at DateTime @default(now())
|
|
completed_at DateTime?
|
|
status String @default("running") // running, success, failed
|
|
result_message String?
|
|
error_message String?
|
|
|
|
process wave_process @relation(fields: [wave_process_id], references: [id])
|
|
|
|
@@index([wave_process_id])
|
|
@@index([started_at])
|
|
@@index([status])
|
|
@@map("wave_process_history")
|
|
}
|
|
|
|
// =============================================================================
|
|
// LTS (LONG-TERM SCHEDULER) TASK DOMAIN
|
|
// =============================================================================
|
|
|
|
// Task types
|
|
model lts_task_type {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
|
|
tasks lts_task[]
|
|
|
|
@@map("lts_task_type")
|
|
}
|
|
|
|
// Scheduled tasks
|
|
model lts_task {
|
|
id String @id @default(cuid())
|
|
lts_task_type_id String
|
|
name String
|
|
description String?
|
|
command String
|
|
is_enabled Boolean @default(true)
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
task_type lts_task_type @relation(fields: [lts_task_type_id], references: [id])
|
|
schedules lts_task_schedule[]
|
|
executions lts_task_execution[]
|
|
|
|
@@map("lts_task")
|
|
}
|
|
|
|
// Task schedule definitions
|
|
model lts_task_schedule {
|
|
id String @id @default(cuid())
|
|
lts_task_id String
|
|
schedule_type String // cron, interval, daily, weekly, monthly
|
|
schedule_value String // cron expression or interval value
|
|
timezone String @default("UTC")
|
|
is_active Boolean @default(true)
|
|
next_run_at DateTime?
|
|
created_at DateTime @default(now())
|
|
updated_at DateTime @updatedAt
|
|
|
|
task lts_task @relation(fields: [lts_task_id], references: [id], onDelete: Cascade)
|
|
|
|
@@index([lts_task_id])
|
|
@@index([next_run_at])
|
|
@@map("lts_task_schedule")
|
|
}
|
|
|
|
// Task execution log
|
|
model lts_task_execution {
|
|
id String @id @default(cuid())
|
|
lts_task_id String
|
|
started_at DateTime @default(now())
|
|
completed_at DateTime?
|
|
status String @default("running") // running, success, failed
|
|
output String?
|
|
error_message String?
|
|
exit_code Int?
|
|
|
|
task lts_task @relation(fields: [lts_task_id], references: [id])
|
|
|
|
@@index([lts_task_id])
|
|
@@index([started_at])
|
|
@@index([status])
|
|
@@map("lts_task_execution")
|
|
}
|