Skip to main content

Database Schema

ConsultFlow uses MongoDB with Mongoose ODM for data persistence.

Collections Overview

CollectionPurpose
usersUser accounts and OAuth tokens
workflowsWorkflow definitions
executionlogsWorkflow execution history

User Schema

Stores user information and Microsoft OAuth tokens.

// src/models/User.ts
import mongoose, { Document, Schema } from 'mongoose'

export interface IUser extends Document {
microsoftId: string
email: string
name: string
accessToken?: string
refreshToken?: string
tokenExpiresAt?: Date
createdAt: Date
updatedAt: Date
}

const UserSchema = new Schema<IUser>(
{
microsoftId: {
type: String,
required: true,
unique: true,
index: true,
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
},
name: {
type: String,
required: true,
},
accessToken: {
type: String,
select: false, // Not returned by default
},
refreshToken: {
type: String,
select: false,
},
tokenExpiresAt: {
type: Date,
},
},
{
timestamps: true, // Adds createdAt, updatedAt
}
)

export const User = mongoose.model<IUser>('User', UserSchema)

User Document Example

{
"_id": "ObjectId('...')",
"microsoftId": "abc123-...",
"email": "john@company.com",
"name": "John Smith",
"tokenExpiresAt": "2024-12-27T00:00:00.000Z",
"createdAt": "2024-12-20T10:00:00.000Z",
"updatedAt": "2024-12-26T15:30:00.000Z"
}

Workflow Schema

Stores workflow definitions with actions and canvas data.

// src/models/Workflow.ts
import mongoose, { Document, Schema } from 'mongoose'

export type WorkflowAction =
| 'generate_mom'
| 'send_email'
| 'create_calendar'
| 'teams_post'
| 'create_ppt'
| 'ai_process'
| 'save_data'
| 'api_call'

export type WorkflowTrigger =
| 'manual'
| 'schedule'
| 'webhook'
| 'transcript'

export interface IWorkflow extends Document {
userId: mongoose.Types.ObjectId
name: string
trigger: WorkflowTrigger
actions: WorkflowAction[]
actionConfigs: Record<string, any>
canvasData?: {
nodes: any[]
edges: any[]
}
createdAt: Date
updatedAt: Date
}

const WorkflowSchema = new Schema<IWorkflow>(
{
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true,
},
name: {
type: String,
required: true,
},
trigger: {
type: String,
enum: ['manual', 'schedule', 'webhook', 'transcript'],
default: 'manual',
},
actions: {
type: [String],
enum: [
'generate_mom',
'send_email',
'create_calendar',
'teams_post',
'create_ppt',
'ai_process',
'save_data',
'api_call',
],
required: true,
},
actionConfigs: {
type: Schema.Types.Mixed,
default: {},
},
canvasData: {
type: Schema.Types.Mixed,
default: null,
},
},
{
timestamps: true,
}
)

export const Workflow = mongoose.model<IWorkflow>('Workflow', WorkflowSchema)

Workflow Document Example

{
"_id": "ObjectId('...')",
"userId": "ObjectId('...')",
"name": "Meeting Follow-up Automation",
"trigger": "manual",
"actions": ["generate_mom", "send_email", "create_calendar"],
"actionConfigs": {
"send_email": {
"to": "team@company.com",
"subject": "Meeting Minutes"
},
"create_calendar": {
"title": "Follow-up Meeting"
}
},
"canvasData": {
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"position": { "x": 100, "y": 100 },
"data": { "label": "Manual Trigger", "actionType": "manual" }
},
{
"id": "action-1",
"type": "action",
"position": { "x": 100, "y": 250 },
"data": { "label": "Generate MOM", "actionType": "generate_mom" }
}
],
"edges": [
{
"id": "edge-1",
"source": "trigger-1",
"target": "action-1"
}
]
},
"createdAt": "2024-12-26T10:00:00.000Z",
"updatedAt": "2024-12-26T10:00:00.000Z"
}

Execution Log Schema

Records workflow execution history.

// src/models/ExecutionLog.ts
import mongoose, { Document, Schema } from 'mongoose'

export interface IExecutionLog extends Document {
userId: mongoose.Types.ObjectId
workflowId: mongoose.Types.ObjectId
status: 'running' | 'completed' | 'failed'
actionsExecuted: string[]
error?: string
executedAt?: Date
createdAt: Date
updatedAt: Date
}

const ExecutionLogSchema = new Schema<IExecutionLog>(
{
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true,
},
workflowId: {
type: Schema.Types.ObjectId,
ref: 'Workflow',
required: true,
},
status: {
type: String,
enum: ['running', 'completed', 'failed'],
default: 'running',
},
actionsExecuted: {
type: [String],
default: [],
},
error: {
type: String,
},
executedAt: {
type: Date,
},
},
{
timestamps: true,
}
)

export const ExecutionLog = mongoose.model<IExecutionLog>(
'ExecutionLog',
ExecutionLogSchema
)

Execution Log Document Example

{
"_id": "ObjectId('...')",
"userId": "ObjectId('...')",
"workflowId": "ObjectId('...')",
"status": "completed",
"actionsExecuted": ["generate_mom", "send_email"],
"error": null,
"executedAt": "2024-12-26T15:30:05.000Z",
"createdAt": "2024-12-26T15:30:00.000Z",
"updatedAt": "2024-12-26T15:30:05.000Z"
}

Indexes

User Indexes

// Unique indexes
db.users.createIndex({ microsoftId: 1 }, { unique: true })
db.users.createIndex({ email: 1 }, { unique: true })

Workflow Indexes

// Query by user
db.workflows.createIndex({ userId: 1 })

// Sort by creation date
db.workflows.createIndex({ userId: 1, createdAt: -1 })

Execution Log Indexes

// Query by user
db.executionlogs.createIndex({ userId: 1 })

// Query by workflow
db.executionlogs.createIndex({ workflowId: 1 })

// Sort by execution date
db.executionlogs.createIndex({ userId: 1, executedAt: -1 })

Database Connection

// src/config/database.ts
import mongoose from 'mongoose'

export const connectDatabase = async () => {
try {
const uri = process.env.MONGODB_URI!

await mongoose.connect(uri, {
// Mongoose 8 uses these defaults
})

console.log('✅ Connected to MongoDB')
} catch (error) {
console.error('❌ MongoDB connection error:', error)
process.exit(1)
}
}

Queries Examples

Find User's Workflows

const workflows = await Workflow.find({ userId: user._id })
.sort({ createdAt: -1 })
.lean()

Get Execution Logs with Workflow Details

const logs = await ExecutionLog.find({ userId: user._id })
.populate('workflowId', 'name actions')
.sort({ executedAt: -1 })
.limit(50)

Update User Tokens

await User.findByIdAndUpdate(userId, {
accessToken: newToken,
refreshToken: newRefreshToken,
tokenExpiresAt: expiresAt,
})

Learn More

See the Authentication Flow for token management details.