mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 04:52:08 +01:00
fix: resolve platform authentication cookie conflicts and session management
- Fix cookie isolation between regular and platform authentication systems - Add custom cookie names for regular auth (app-auth.session-token) vs platform auth (platform-auth.session-token) - Remove restrictive cookie path from platform auth to allow proper session access - Create custom usePlatformSession hook to bypass NextAuth useSession routing issues - Fix platform dashboard authentication and eliminate redirect loops - Add proper NEXTAUTH_SECRET configuration - Enhance platform login with autocomplete attributes - Update TODO with PR #20 feedback actions and mark platform features complete The platform management dashboard now has fully functional authentication with proper session isolation between regular users and platform admins.
This commit is contained in:
39
TODO
39
TODO
@ -10,10 +10,10 @@
|
||||
- [x] Add company creation workflows
|
||||
- [x] Add basic platform API endpoints with tests
|
||||
- [x] Create stunning SaaS landing page with modern design
|
||||
- [ ] Add company editing/management workflows
|
||||
- [ ] Create company suspension/activation UI features
|
||||
- [ ] Add proper SEO metadata and OpenGraph tags
|
||||
- [ ] Add user management within companies from platform
|
||||
- [x] Add company editing/management workflows
|
||||
- [x] Create company suspension/activation UI features
|
||||
- [x] Add proper SEO metadata and OpenGraph tags
|
||||
- [x] Add user management within companies from platform
|
||||
- [ ] Add AI model management UI
|
||||
- [ ] Add cost tracking/quotas UI
|
||||
|
||||
@ -61,6 +61,37 @@
|
||||
|
||||
## High Priority
|
||||
|
||||
### PR #20 Feedback Actions (Code Review)
|
||||
- [ ] **Fix Environment Variable Testing**
|
||||
- [ ] Replace process.env access with proper environment mocking in tests
|
||||
- [ ] Update existing tests to avoid direct environment variable dependencies
|
||||
- [ ] Add environment validation tests for critical config values
|
||||
|
||||
- [ ] **Enforce Zero Accessibility Violations**
|
||||
- [ ] Set Playwright accessibility tests to fail on any violations (not just warn)
|
||||
- [ ] Add accessibility regression tests for all major components
|
||||
- [ ] Implement accessibility checklist for new components
|
||||
|
||||
- [ ] **Improve Error Handling with Custom Error Classes**
|
||||
- [ ] Create custom error classes for different error types (ValidationError, AuthError, etc.)
|
||||
- [ ] Replace generic Error throws with specific error classes
|
||||
- [ ] Add proper error logging and monitoring integration
|
||||
|
||||
- [ ] **Refactor Long className Strings**
|
||||
- [ ] Extract complex className combinations into utility functions
|
||||
- [ ] Consider using cn() utility from utils for cleaner class composition
|
||||
- [ ] Break down overly complex className props into semantic components
|
||||
|
||||
- [ ] **Add Dark Mode Accessibility Tests**
|
||||
- [ ] Create comprehensive test suite for dark mode color contrast
|
||||
- [ ] Verify focus indicators work properly in both light and dark modes
|
||||
- [ ] Test screen reader compatibility with theme switching
|
||||
|
||||
- [ ] **Fix Platform Login Authentication Issue**
|
||||
- [ ] NEXTAUTH_SECRET was using placeholder value (FIXED)
|
||||
- [ ] Investigate platform cookie path restrictions in /platform auth
|
||||
- [ ] Test platform login flow end-to-end after fixes
|
||||
|
||||
### Testing & Quality Assurance
|
||||
- [ ] Add comprehensive test coverage for API endpoints (currently minimal)
|
||||
- [ ] Implement integration tests for the data processing pipeline
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
@ -48,8 +47,39 @@ interface DashboardData {
|
||||
};
|
||||
}
|
||||
|
||||
// Custom hook for platform session
|
||||
function usePlatformSession() {
|
||||
const [session, setSession] = useState<any>(null);
|
||||
const [status, setStatus] = useState<"loading" | "authenticated" | "unauthenticated">("loading");
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSession = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/platform/auth/session");
|
||||
const sessionData = await response.json();
|
||||
|
||||
if (sessionData?.user?.isPlatformUser) {
|
||||
setSession(sessionData);
|
||||
setStatus("authenticated");
|
||||
} else {
|
||||
setSession(null);
|
||||
setStatus("unauthenticated");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Platform session fetch error:", error);
|
||||
setSession(null);
|
||||
setStatus("unauthenticated");
|
||||
}
|
||||
};
|
||||
|
||||
fetchSession();
|
||||
}, []);
|
||||
|
||||
return { data: session, status };
|
||||
}
|
||||
|
||||
export default function PlatformDashboard() {
|
||||
const { data: session, status } = useSession();
|
||||
const { data: session, status } = usePlatformSession();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const [dashboardData, setDashboardData] = useState<DashboardData | null>(null);
|
||||
@ -67,7 +97,7 @@ export default function PlatformDashboard() {
|
||||
useEffect(() => {
|
||||
if (status === "loading") return;
|
||||
|
||||
if (!session?.user?.isPlatformUser) {
|
||||
if (status === "unauthenticated" || !session?.user?.isPlatformUser) {
|
||||
router.push("/platform/login");
|
||||
return;
|
||||
}
|
||||
@ -155,7 +185,7 @@ export default function PlatformDashboard() {
|
||||
);
|
||||
}
|
||||
|
||||
if (!session?.user?.isPlatformUser) {
|
||||
if (status === "unauthenticated" || !session?.user?.isPlatformUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ export default function PlatformLayout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<SessionProvider>
|
||||
<SessionProvider basePath="/api/platform/auth">
|
||||
{children}
|
||||
<Toaster />
|
||||
</SessionProvider>
|
||||
|
||||
@ -31,14 +31,9 @@ export default function PlatformLoginPage() {
|
||||
|
||||
if (result?.error) {
|
||||
setError("Invalid credentials");
|
||||
} else {
|
||||
// Verify the session has platform access
|
||||
const session = await getSession();
|
||||
if (session?.user?.isPlatformUser) {
|
||||
router.push("/platform/dashboard");
|
||||
} else {
|
||||
setError("Platform access required");
|
||||
}
|
||||
} else if (result?.ok) {
|
||||
// Login successful, redirect to dashboard
|
||||
router.push("/platform/dashboard");
|
||||
}
|
||||
} catch (error) {
|
||||
setError("An error occurred during login");
|
||||
@ -73,6 +68,7 @@ export default function PlatformLoginPage() {
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
disabled={isLoading}
|
||||
autoComplete="email"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -85,6 +81,7 @@ export default function PlatformLoginPage() {
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
disabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
12
lib/auth.ts
12
lib/auth.ts
@ -80,6 +80,18 @@ export const authOptions: NextAuthOptions = {
|
||||
],
|
||||
session: {
|
||||
strategy: "jwt",
|
||||
maxAge: 24 * 60 * 60, // 24 hours for regular users
|
||||
},
|
||||
cookies: {
|
||||
sessionToken: {
|
||||
name: `app-auth.session-token`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, user }) {
|
||||
|
||||
@ -79,7 +79,7 @@ export const platformAuthOptions: NextAuthOptions = {
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/platform",
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
|
||||
@ -10,56 +10,72 @@ datasource db {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * PLATFORM USER (super-admin for Notso AI)
|
||||
/// * Platform-level users who can manage companies and platform-wide settings
|
||||
/// * Separate from Company users for platform management isolation
|
||||
/// * PLATFORM USER (super-admin for Notso AI)
|
||||
/// * Platform-level users who can manage companies and platform-wide settings
|
||||
/// * Separate from Company users for platform management isolation
|
||||
model PlatformUser {
|
||||
id String @id @default(uuid())
|
||||
email String @unique @db.VarChar(255) /// Platform user email address
|
||||
password String @db.VarChar(255) /// Hashed password for platform authentication
|
||||
role PlatformUserRole @default(ADMIN) /// Platform permission level
|
||||
name String @db.VarChar(255) /// Display name for platform user
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
id String @id @default(uuid())
|
||||
/// Platform user email address
|
||||
email String @unique @db.VarChar(255)
|
||||
/// Hashed password for platform authentication
|
||||
password String @db.VarChar(255)
|
||||
/// Platform permission level
|
||||
role PlatformUserRole @default(ADMIN)
|
||||
/// Display name for platform user
|
||||
name String @db.VarChar(255)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
|
||||
@@index([email])
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * COMPANY (multi-tenant root)
|
||||
/// * Root entity for multi-tenant architecture
|
||||
/// * Each company has isolated data with own users, sessions, and AI model configurations
|
||||
/// * COMPANY (multi-tenant root)
|
||||
/// * Root entity for multi-tenant architecture
|
||||
/// * Each company has isolated data with own users, sessions, and AI model configurations
|
||||
model Company {
|
||||
id String @id @default(uuid())
|
||||
name String @db.VarChar(255) /// Company name for display and filtering
|
||||
status CompanyStatus @default(ACTIVE) /// Company status for suspension/activation
|
||||
csvUrl String @db.Text /// URL endpoint for CSV data import
|
||||
csvUsername String? @db.VarChar(255) /// Optional HTTP auth username for CSV endpoint
|
||||
csvPassword String? @db.VarChar(255) /// Optional HTTP auth password for CSV endpoint
|
||||
dashboardOpts Json? @db.JsonB /// Company-specific dashboard configuration (theme, layout, etc.)
|
||||
/// Company name for display and filtering
|
||||
name String @db.VarChar(255)
|
||||
/// Company status for suspension/activation
|
||||
status CompanyStatus @default(ACTIVE)
|
||||
/// URL endpoint for CSV data import
|
||||
csvUrl String
|
||||
/// Optional HTTP auth username for CSV endpoint
|
||||
csvUsername String? @db.VarChar(255)
|
||||
/// Optional HTTP auth password for CSV endpoint
|
||||
csvPassword String? @db.VarChar(255)
|
||||
/// Company-specific dashboard configuration (theme, layout, etc.)
|
||||
dashboardOpts Json?
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
companyAiModels CompanyAIModel[] /// AI models assigned to this company
|
||||
sessions Session[] /// All processed sessions for this company
|
||||
imports SessionImport[] /// Raw CSV import data for this company
|
||||
users User[] @relation("CompanyUsers") /// Users belonging to this company
|
||||
companyAiModels CompanyAIModel[]
|
||||
sessions Session[]
|
||||
imports SessionImport[]
|
||||
users User[] @relation("CompanyUsers")
|
||||
|
||||
@@index([name])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * USER (authentication accounts)
|
||||
/// * Application users with role-based access control
|
||||
/// * Each user belongs to exactly one company for data isolation
|
||||
/// * USER (authentication accounts)
|
||||
/// * Application users with role-based access control
|
||||
/// * Each user belongs to exactly one company for data isolation
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique @db.VarChar(255) /// User email address, must be unique across all companies
|
||||
password String @db.VarChar(255) /// Hashed password for authentication
|
||||
role UserRole @default(USER) /// User permission level within their company
|
||||
companyId String /// Foreign key to Company - enforces data isolation
|
||||
resetToken String? @db.VarChar(255) /// Temporary token for password reset functionality
|
||||
resetTokenExpiry DateTime? @db.Timestamptz(6) /// Expiration time for reset token
|
||||
/// User email address, must be unique across all companies
|
||||
email String @unique @db.VarChar(255)
|
||||
/// Hashed password for authentication
|
||||
password String @db.VarChar(255)
|
||||
/// User permission level within their company
|
||||
role UserRole @default(USER)
|
||||
/// Foreign key to Company - enforces data isolation
|
||||
companyId String
|
||||
/// Temporary token for password reset functionality
|
||||
resetToken String? @db.VarChar(255)
|
||||
/// Expiration time for reset token
|
||||
resetTokenExpiry DateTime? @db.Timestamptz(6)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
company Company @relation("CompanyUsers", fields: [companyId], references: [id], onDelete: Cascade)
|
||||
@ -69,47 +85,62 @@ model User {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * SESSION (processed conversation data)
|
||||
/// * Normalized session data derived from raw CSV imports
|
||||
/// * Contains AI-enhanced data like sentiment analysis and categorization
|
||||
/// * 1:1 relationship with SessionImport via importId
|
||||
/// * SESSION (processed conversation data)
|
||||
/// * Normalized session data derived from raw CSV imports
|
||||
/// * Contains AI-enhanced data like sentiment analysis and categorization
|
||||
/// * 1:1 relationship with SessionImport via importId
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
companyId String /// Foreign key to Company for data isolation
|
||||
importId String? @unique /// Optional 1:1 link to source SessionImport record
|
||||
/// Foreign key to Company for data isolation
|
||||
companyId String
|
||||
/// Optional 1:1 link to source SessionImport record
|
||||
importId String? @unique
|
||||
/// Session timing and basic data
|
||||
startTime DateTime @db.Timestamptz(6) /// When the conversation started
|
||||
endTime DateTime @db.Timestamptz(6) /// When the conversation ended
|
||||
ipAddress String? @db.Inet /// Client IP address (IPv4/IPv6)
|
||||
country String? @db.VarChar(3) /// ISO 3166-1 alpha-3 country code
|
||||
fullTranscriptUrl String? @db.Text /// URL to external transcript source
|
||||
avgResponseTime Float? @db.Real /// Average response time in seconds
|
||||
initialMsg String? @db.Text /// First message in the conversation
|
||||
language String? @db.VarChar(10) /// ISO 639 language code
|
||||
messagesSent Int? /// Total number of messages in session
|
||||
/// When the conversation started
|
||||
startTime DateTime @db.Timestamptz(6)
|
||||
/// When the conversation ended
|
||||
endTime DateTime @db.Timestamptz(6)
|
||||
/// Client IP address (IPv4/IPv6)
|
||||
ipAddress String? @db.Inet
|
||||
/// ISO 3166-1 alpha-3 country code
|
||||
country String? @db.VarChar(3)
|
||||
/// URL to external transcript source
|
||||
fullTranscriptUrl String?
|
||||
/// Average response time in seconds
|
||||
avgResponseTime Float? @db.Real
|
||||
/// First message in the conversation
|
||||
initialMsg String?
|
||||
/// ISO 639 language code
|
||||
language String? @db.VarChar(10)
|
||||
/// Total number of messages in session
|
||||
messagesSent Int?
|
||||
/// AI-enhanced analysis fields
|
||||
sentiment SentimentCategory? /// AI-determined overall sentiment
|
||||
escalated Boolean? /// Whether session was escalated to human
|
||||
forwardedHr Boolean? /// Whether session was forwarded to HR
|
||||
category SessionCategory? /// AI-determined conversation category
|
||||
summary String? @db.Text /// AI-generated session summary
|
||||
/// AI-determined overall sentiment
|
||||
sentiment SentimentCategory?
|
||||
/// Whether session was escalated to human
|
||||
escalated Boolean?
|
||||
/// Whether session was forwarded to HR
|
||||
forwardedHr Boolean?
|
||||
/// AI-determined conversation category
|
||||
category SessionCategory?
|
||||
/// AI-generated session summary
|
||||
summary String?
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
/// Related data
|
||||
aiProcessingRequests AIProcessingRequest[] /// All AI API calls made for this session
|
||||
messages Message[] /// Individual messages in conversation order
|
||||
aiProcessingRequests AIProcessingRequest[]
|
||||
messages Message[]
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
import SessionImport? @relation("ImportToSession", fields: [importId], references: [id])
|
||||
processingStatus SessionProcessingStatus[] /// Pipeline stage tracking
|
||||
sessionQuestions SessionQuestion[] /// Questions extracted from conversation
|
||||
processingStatus SessionProcessingStatus[]
|
||||
sessionQuestions SessionQuestion[]
|
||||
|
||||
@@index([companyId, startTime]) /// Primary query pattern: company sessions by time
|
||||
@@index([companyId, sentiment]) /// Filter sessions by sentiment within company
|
||||
@@index([companyId, category]) /// Filter sessions by category within company
|
||||
@@index([companyId, startTime])
|
||||
@@index([companyId, sentiment])
|
||||
@@index([companyId, category])
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * 2. Raw CSV row (pure data storage) ----------
|
||||
/// * 2. Raw CSV row (pure data storage) ----------
|
||||
model SessionImport {
|
||||
id String @id @default(uuid())
|
||||
companyId String
|
||||
@ -123,13 +154,13 @@ model SessionImport {
|
||||
sentimentRaw String? @db.VarChar(50)
|
||||
escalatedRaw String? @db.VarChar(50)
|
||||
forwardedHrRaw String? @db.VarChar(50)
|
||||
fullTranscriptUrl String? @db.Text
|
||||
fullTranscriptUrl String?
|
||||
avgResponseTimeSeconds Float? @db.Real
|
||||
tokens Int?
|
||||
tokensEur Float? @db.Real
|
||||
category String? @db.VarChar(255)
|
||||
initialMessage String? @db.Text
|
||||
rawTranscriptContent String? @db.Text
|
||||
initialMessage String?
|
||||
rawTranscriptContent String?
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
session Session? @relation("ImportToSession")
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
@ -140,13 +171,13 @@ model SessionImport {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * MESSAGE (individual lines)
|
||||
/// * MESSAGE (individual lines)
|
||||
model Message {
|
||||
id String @id @default(uuid())
|
||||
sessionId String
|
||||
timestamp DateTime? @db.Timestamptz(6)
|
||||
role String @db.VarChar(50)
|
||||
content String @db.Text
|
||||
content String
|
||||
order Int
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
@ -157,7 +188,7 @@ model Message {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * UNIFIED PROCESSING STATUS TRACKING
|
||||
/// * UNIFIED PROCESSING STATUS TRACKING
|
||||
model SessionProcessingStatus {
|
||||
id String @id @default(uuid())
|
||||
sessionId String
|
||||
@ -165,9 +196,9 @@ model SessionProcessingStatus {
|
||||
status ProcessingStatus @default(PENDING)
|
||||
startedAt DateTime? @db.Timestamptz(6)
|
||||
completedAt DateTime? @db.Timestamptz(6)
|
||||
errorMessage String? @db.Text
|
||||
errorMessage String?
|
||||
retryCount Int @default(0)
|
||||
metadata Json? @db.JsonB
|
||||
metadata Json?
|
||||
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([sessionId, stage])
|
||||
@ -177,10 +208,10 @@ model SessionProcessingStatus {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * QUESTION MANAGEMENT (separate from Session for better analytics)
|
||||
/// * QUESTION MANAGEMENT (separate from Session for better analytics)
|
||||
model Question {
|
||||
id String @id @default(uuid())
|
||||
content String @unique @db.Text
|
||||
content String @unique
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
sessionQuestions SessionQuestion[]
|
||||
}
|
||||
@ -201,7 +232,7 @@ model SessionQuestion {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * AI PROCESSING COST TRACKING
|
||||
/// * AI PROCESSING COST TRACKING
|
||||
model AIProcessingRequest {
|
||||
id String @id @default(uuid())
|
||||
sessionId String
|
||||
@ -223,7 +254,7 @@ model AIProcessingRequest {
|
||||
totalCostEur Float @db.Real
|
||||
processingType String @db.VarChar(100)
|
||||
success Boolean
|
||||
errorMessage String? @db.Text
|
||||
errorMessage String?
|
||||
requestedAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
completedAt DateTime? @db.Timestamptz(6)
|
||||
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
@ -236,7 +267,7 @@ model AIProcessingRequest {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * AI Model definitions (without pricing)
|
||||
/// * AI Model definitions (without pricing)
|
||||
model AIModel {
|
||||
id String @id @default(uuid())
|
||||
name String @unique @db.VarChar(100)
|
||||
@ -253,7 +284,7 @@ model AIModel {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * Time-based pricing for AI models
|
||||
/// * Time-based pricing for AI models
|
||||
model AIModelPricing {
|
||||
id String @id @default(uuid())
|
||||
aiModelId String
|
||||
@ -269,7 +300,7 @@ model AIModelPricing {
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * Company-specific AI model assignments
|
||||
/// * Company-specific AI model assignments
|
||||
model CompanyAIModel {
|
||||
id String @id @default(uuid())
|
||||
companyId String
|
||||
@ -283,70 +314,102 @@ model CompanyAIModel {
|
||||
@@index([companyId, isDefault])
|
||||
}
|
||||
|
||||
/// *
|
||||
/// * ENUMS – typed constants for better data integrity
|
||||
///
|
||||
|
||||
/// Platform-level user roles for Notso AI team
|
||||
enum PlatformUserRole {
|
||||
SUPER_ADMIN /// Full platform access, can create/suspend companies
|
||||
ADMIN /// Platform administration, company management
|
||||
SUPPORT /// Customer support access, read-only company access
|
||||
/// Full platform access, can create/suspend companies
|
||||
SUPER_ADMIN
|
||||
/// Platform administration, company management
|
||||
ADMIN
|
||||
/// Customer support access, read-only company access
|
||||
SUPPORT
|
||||
}
|
||||
|
||||
/// User permission levels within a company
|
||||
enum UserRole {
|
||||
ADMIN /// Full access to company data and settings
|
||||
USER /// Standard access to view and interact with data
|
||||
AUDITOR /// Read-only access for compliance and auditing
|
||||
/// Full access to company data and settings
|
||||
ADMIN
|
||||
/// Standard access to view and interact with data
|
||||
USER
|
||||
/// Read-only access for compliance and auditing
|
||||
AUDITOR
|
||||
}
|
||||
|
||||
/// Company operational status
|
||||
enum CompanyStatus {
|
||||
ACTIVE /// Company is operational and can access all features
|
||||
SUSPENDED /// Company access is temporarily disabled
|
||||
TRIAL /// Company is in trial period with potential limitations
|
||||
ARCHIVED /// Company is archived and data is read-only
|
||||
/// Company is operational and can access all features
|
||||
ACTIVE
|
||||
/// Company access is temporarily disabled
|
||||
SUSPENDED
|
||||
/// Company is in trial period with potential limitations
|
||||
TRIAL
|
||||
/// Company is archived and data is read-only
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
/// AI-determined sentiment categories for sessions
|
||||
enum SentimentCategory {
|
||||
POSITIVE /// Customer expressed satisfaction or positive emotions
|
||||
NEUTRAL /// Neutral tone or mixed emotions
|
||||
NEGATIVE /// Customer expressed frustration or negative emotions
|
||||
/// Customer expressed satisfaction or positive emotions
|
||||
POSITIVE
|
||||
/// Neutral tone or mixed emotions
|
||||
NEUTRAL
|
||||
/// Customer expressed frustration or negative emotions
|
||||
NEGATIVE
|
||||
}
|
||||
|
||||
/// AI-determined conversation categories based on content analysis
|
||||
enum SessionCategory {
|
||||
SCHEDULE_HOURS /// Questions about work schedules and hours
|
||||
LEAVE_VACATION /// Vacation requests and leave policies
|
||||
SICK_LEAVE_RECOVERY /// Sick leave and recovery-related discussions
|
||||
SALARY_COMPENSATION /// Salary, benefits, and compensation questions
|
||||
CONTRACT_HOURS /// Contract terms and working hours
|
||||
ONBOARDING /// New employee onboarding processes
|
||||
OFFBOARDING /// Employee departure and offboarding
|
||||
WORKWEAR_STAFF_PASS /// Equipment, uniforms, and access cards
|
||||
TEAM_CONTACTS /// Team directory and contact information
|
||||
PERSONAL_QUESTIONS /// Personal HR matters and private concerns
|
||||
ACCESS_LOGIN /// System access and login issues
|
||||
SOCIAL_QUESTIONS /// Social events and company culture
|
||||
UNRECOGNIZED_OTHER /// Conversations that don't fit other categories
|
||||
/// Questions about work schedules and hours
|
||||
SCHEDULE_HOURS
|
||||
/// Vacation requests and leave policies
|
||||
LEAVE_VACATION
|
||||
/// Sick leave and recovery-related discussions
|
||||
SICK_LEAVE_RECOVERY
|
||||
/// Salary, benefits, and compensation questions
|
||||
SALARY_COMPENSATION
|
||||
/// Contract terms and working hours
|
||||
CONTRACT_HOURS
|
||||
/// New employee onboarding processes
|
||||
ONBOARDING
|
||||
/// Employee departure and offboarding
|
||||
OFFBOARDING
|
||||
/// Equipment, uniforms, and access cards
|
||||
WORKWEAR_STAFF_PASS
|
||||
/// Team directory and contact information
|
||||
TEAM_CONTACTS
|
||||
/// Personal HR matters and private concerns
|
||||
PERSONAL_QUESTIONS
|
||||
/// System access and login issues
|
||||
ACCESS_LOGIN
|
||||
/// Social events and company culture
|
||||
SOCIAL_QUESTIONS
|
||||
/// Conversations that don't fit other categories
|
||||
UNRECOGNIZED_OTHER
|
||||
}
|
||||
|
||||
/// Processing pipeline stages for session data transformation
|
||||
enum ProcessingStage {
|
||||
CSV_IMPORT /// Initial import of raw CSV data into SessionImport
|
||||
TRANSCRIPT_FETCH /// Fetching transcript content from external URLs
|
||||
SESSION_CREATION /// Converting SessionImport to normalized Session
|
||||
AI_ANALYSIS /// AI processing for sentiment, categorization, summaries
|
||||
QUESTION_EXTRACTION /// Extracting questions from conversation content
|
||||
/// Initial import of raw CSV data into SessionImport
|
||||
CSV_IMPORT
|
||||
/// Fetching transcript content from external URLs
|
||||
TRANSCRIPT_FETCH
|
||||
/// Converting SessionImport to normalized Session
|
||||
SESSION_CREATION
|
||||
/// AI processing for sentiment, categorization, summaries
|
||||
AI_ANALYSIS
|
||||
/// Extracting questions from conversation content
|
||||
QUESTION_EXTRACTION
|
||||
}
|
||||
|
||||
/// Status of each processing stage
|
||||
enum ProcessingStatus {
|
||||
PENDING /// Stage is queued for processing
|
||||
IN_PROGRESS /// Stage is currently being processed
|
||||
COMPLETED /// Stage completed successfully
|
||||
FAILED /// Stage failed with errors
|
||||
SKIPPED /// Stage was intentionally skipped
|
||||
/// Stage is queued for processing
|
||||
PENDING
|
||||
/// Stage is currently being processed
|
||||
IN_PROGRESS
|
||||
/// Stage completed successfully
|
||||
COMPLETED
|
||||
/// Stage failed with errors
|
||||
FAILED
|
||||
/// Stage was intentionally skipped
|
||||
SKIPPED
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user