mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 12:32:10 +01:00
feat: Refactor database schema to enhance relationships and data types for Company, User, Session, and Message models
This commit is contained in:
108
TODO.md
108
TODO.md
@ -1,108 +0,0 @@
|
|||||||
# TODO.md
|
|
||||||
|
|
||||||
## Dashboard Integration
|
|
||||||
|
|
||||||
- [ ] **Resolve `GeographicMap.tsx` and `ResponseTimeDistribution.tsx` data simulation**
|
|
||||||
- Investigate integrating real data sources with server-side analytics
|
|
||||||
- Replace simulated data mentioned in `docs/dashboard-components.md`
|
|
||||||
|
|
||||||
## Component Specific
|
|
||||||
|
|
||||||
- [ ] **Implement robust emailing of temporary passwords**
|
|
||||||
|
|
||||||
- File: `pages/api/dashboard/users.ts`
|
|
||||||
- Set up proper email service integration
|
|
||||||
|
|
||||||
- [x] **Session page improvements** ✅
|
|
||||||
- File: `app/dashboard/sessions/page.tsx`
|
|
||||||
- Implemented pagination, advanced filtering, and sorting
|
|
||||||
|
|
||||||
## File Cleanup
|
|
||||||
|
|
||||||
- [x] **Remove backup files** ✅
|
|
||||||
- Reviewed and removed `.bak` and `.new` files after integration
|
|
||||||
- Cleaned up `GeographicMap.tsx.bak`, `SessionDetails.tsx.bak`, `SessionDetails.tsx.new`
|
|
||||||
|
|
||||||
## Database Schema Improvements
|
|
||||||
|
|
||||||
- [ ] **Update EndTime field**
|
|
||||||
|
|
||||||
- Make `endTime` field nullable in Prisma schema to match TypeScript interfaces
|
|
||||||
|
|
||||||
- [ ] **Add database indices**
|
|
||||||
|
|
||||||
- Add appropriate indices to improve query performance
|
|
||||||
- Focus on dashboard metrics and session listing queries
|
|
||||||
|
|
||||||
- [ ] **Implement production email service**
|
|
||||||
- Replace console logging in `lib/sendEmail.ts`
|
|
||||||
- Consider providers: Nodemailer, SendGrid, AWS SES
|
|
||||||
|
|
||||||
## General Enhancements & Features
|
|
||||||
|
|
||||||
- [ ] **Real-time updates**
|
|
||||||
|
|
||||||
- Implement for dashboard and session list
|
|
||||||
- Consider WebSockets or Server-Sent Events
|
|
||||||
|
|
||||||
- [ ] **Data export functionality**
|
|
||||||
|
|
||||||
- Allow users (especially admins) to export session data
|
|
||||||
- Support CSV format initially
|
|
||||||
|
|
||||||
- [ ] **Customizable dashboard**
|
|
||||||
- Allow users to customize dashboard view
|
|
||||||
- Let users choose which metrics/charts are most important
|
|
||||||
|
|
||||||
## Testing & Quality Assurance
|
|
||||||
|
|
||||||
- [ ] **Comprehensive testing suite**
|
|
||||||
|
|
||||||
- [ ] Unit tests for utility functions and API logic
|
|
||||||
- [ ] Integration tests for API endpoints with database
|
|
||||||
- [ ] End-to-end tests for user flows (Playwright or Cypress)
|
|
||||||
|
|
||||||
- [ ] **Error monitoring and logging**
|
|
||||||
|
|
||||||
- Integrate robust error monitoring service (Sentry)
|
|
||||||
- Enhance server-side logging
|
|
||||||
|
|
||||||
- [ ] **Accessibility improvements**
|
|
||||||
- Review application against WCAG guidelines
|
|
||||||
- Improve keyboard navigation and screen reader compatibility
|
|
||||||
- Check color contrast ratios
|
|
||||||
|
|
||||||
## Security Enhancements
|
|
||||||
|
|
||||||
- [x] **Password reset functionality** ✅
|
|
||||||
|
|
||||||
- Implemented secure password reset mechanism
|
|
||||||
- Files: `app/forgot-password/page.tsx`, `app/reset-password/page.tsx`, `pages/api/forgot-password.ts`, `pages/api/reset-password.ts`
|
|
||||||
|
|
||||||
- [ ] **Two-Factor Authentication (2FA)**
|
|
||||||
|
|
||||||
- Consider adding 2FA, especially for admin accounts
|
|
||||||
|
|
||||||
- [ ] **Input validation and sanitization**
|
|
||||||
- Review all user inputs (API request bodies, query parameters)
|
|
||||||
- Ensure proper validation and sanitization
|
|
||||||
|
|
||||||
## Code Quality & Development
|
|
||||||
|
|
||||||
- [ ] **Code review process**
|
|
||||||
|
|
||||||
- Enforce code reviews for all changes
|
|
||||||
|
|
||||||
- [ ] **Environment configuration**
|
|
||||||
|
|
||||||
- Ensure secure management of environment-specific configurations
|
|
||||||
|
|
||||||
- [ ] **Dependency management**
|
|
||||||
|
|
||||||
- Periodically review dependencies for vulnerabilities
|
|
||||||
- Keep dependencies updated
|
|
||||||
|
|
||||||
- [ ] **Documentation updates**
|
|
||||||
- [ ] Ensure `docs/dashboard-components.md` reflects actual implementations
|
|
||||||
- [ ] Verify "Dashboard Enhancements" are consistently applied
|
|
||||||
- [ ] Update documentation for improved layout and visual hierarchies
|
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"prisma:migrate": "prisma migrate dev",
|
"prisma:migrate": "prisma migrate dev",
|
||||||
"prisma:seed": "node prisma/seed.mjs",
|
"prisma:seed": "node prisma/seed.mjs",
|
||||||
"prisma:push": "prisma db push",
|
"prisma:push": "prisma db push",
|
||||||
|
"prisma:push:force": "prisma db push --force-reset",
|
||||||
"prisma:studio": "prisma studio",
|
"prisma:studio": "prisma studio",
|
||||||
"start": "node server.mjs",
|
"start": "node server.mjs",
|
||||||
"lint:md": "markdownlint-cli2 \"**/*.md\" \"!.trunk/**\" \"!.venv/**\" \"!node_modules/**\"",
|
"lint:md": "markdownlint-cli2 \"**/*.md\" \"!.trunk/**\" \"!.venv/**\" \"!node_modules/**\"",
|
||||||
|
|||||||
@ -1,74 +1,166 @@
|
|||||||
// Database schema, one company = one org, linked to users and CSV config
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "sqlite" // still OK for local/dev; use Postgres in prod
|
||||||
url = "file:./dev.db"
|
url = "file:./dev.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ENUMS – fewer magic strings
|
||||||
|
*/
|
||||||
|
enum UserRole {
|
||||||
|
ADMIN
|
||||||
|
USER
|
||||||
|
AUDITOR
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SentimentCategory {
|
||||||
|
POSITIVE
|
||||||
|
NEUTRAL
|
||||||
|
NEGATIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* COMPANY (multi-tenant root)
|
||||||
|
*/
|
||||||
model Company {
|
model Company {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String
|
name String
|
||||||
csvUrl String // where to fetch CSV
|
csvUrl String
|
||||||
csvUsername String? // for basic auth
|
csvUsername String?
|
||||||
csvPassword String?
|
csvPassword String?
|
||||||
sentimentAlert Float? // e.g. alert threshold for negative chats
|
sentimentAlert Float?
|
||||||
dashboardOpts String? // JSON blob for per-company dashboard preferences
|
dashboardOpts Json? // JSON column instead of opaque string
|
||||||
users User[]
|
|
||||||
|
users User[] @relation("CompanyUsers")
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
|
imports SessionImport[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USER (auth accounts)
|
||||||
|
*/
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
email String @unique
|
email String @unique
|
||||||
password String // hashed, use bcrypt
|
password String
|
||||||
company Company @relation(fields: [companyId], references: [id])
|
role UserRole @default(USER)
|
||||||
|
|
||||||
|
company Company @relation("CompanyUsers", fields: [companyId], references: [id], onDelete: Cascade)
|
||||||
companyId String
|
companyId String
|
||||||
role String // 'admin' | 'user' | 'auditor'
|
|
||||||
resetToken String?
|
resetToken String?
|
||||||
resetTokenExpiry DateTime?
|
resetTokenExpiry DateTime?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SESSION ↔ SESSIONIMPORT (1-to-1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Normalised session ---------------------------
|
||||||
|
*/
|
||||||
model Session {
|
model Session {
|
||||||
id String @id
|
id String @id @default(uuid())
|
||||||
company Company @relation(fields: [companyId], references: [id])
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||||
companyId String
|
companyId String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1-to-1 link back to the import row
|
||||||
|
*/
|
||||||
|
import SessionImport? @relation("ImportToSession", fields: [importId], references: [id])
|
||||||
|
importId String? @unique
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session-level data …
|
||||||
|
*/
|
||||||
startTime DateTime
|
startTime DateTime
|
||||||
endTime DateTime
|
endTime DateTime
|
||||||
|
// … whatever other scalar fields you have here …
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------- the missing opposite side ----------
|
||||||
|
*/
|
||||||
|
messages Message[] // <-- satisfies Message.session
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([companyId, startTime])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2. Raw CSV row waiting to be processed ----------
|
||||||
|
*/
|
||||||
|
enum ImportStatus {
|
||||||
|
QUEUED
|
||||||
|
PROCESSING
|
||||||
|
DONE
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
model SessionImport {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||||
|
companyId String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1-to-1 back-relation; NO fields/references here
|
||||||
|
*/
|
||||||
|
session Session? @relation("ImportToSession")
|
||||||
|
|
||||||
|
// ─── 16 CSV columns 1-to-1 ────────────────────────
|
||||||
|
externalSessionId String @unique // value from CSV column 1
|
||||||
|
startTimeRaw String
|
||||||
|
endTimeRaw String
|
||||||
ipAddress String?
|
ipAddress String?
|
||||||
country String?
|
countryCode String?
|
||||||
language String?
|
language String?
|
||||||
messagesSent Int?
|
messagesSent Int?
|
||||||
sentiment Float? // Original sentiment score (float)
|
sentimentRaw String?
|
||||||
sentimentCategory String? // "positive", "neutral", "negative" from OpenAPI
|
escalatedRaw String?
|
||||||
escalated Boolean?
|
forwardedHrRaw String?
|
||||||
forwardedHr Boolean?
|
|
||||||
fullTranscriptUrl String?
|
fullTranscriptUrl String?
|
||||||
avgResponseTime Float?
|
avgResponseTimeSeconds Float?
|
||||||
tokens Int?
|
tokens Int?
|
||||||
tokensEur Float?
|
tokensEur Float?
|
||||||
category String?
|
category String?
|
||||||
initialMsg String?
|
initialMessage String?
|
||||||
processed Boolean @default(false) // Flag for post-processing status
|
|
||||||
questions String? // JSON array of questions asked by user
|
// ─── bookkeeping ─────────────────────────────────
|
||||||
summary String? // Brief summary of the conversation
|
status ImportStatus @default(QUEUED)
|
||||||
messages Message[] // Relation to parsed messages
|
errorMsg String?
|
||||||
|
processedAt DateTime?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@unique([companyId, externalSessionId]) // idempotent re-imports
|
||||||
|
@@index([status])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MESSAGE (individual lines)
|
||||||
|
*/
|
||||||
model Message {
|
model Message {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
|
|
||||||
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||||
sessionId String
|
sessionId String
|
||||||
timestamp DateTime // When the message was sent
|
|
||||||
role String // "User", "Assistant", "System", etc.
|
timestamp DateTime
|
||||||
content String // The message content
|
role String // "user" | "assistant" | "system" – free-form keeps migration easy
|
||||||
order Int // Order within the conversation (0, 1, 2, ...)
|
content String
|
||||||
|
order Int
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
@@index([sessionId, order]) // Index for efficient ordering queries
|
@@unique([sessionId, order]) // guards against duplicate order values
|
||||||
|
@@index([sessionId, order])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user