tractatus/src/models/ScheduledTask.model.js
TheFlow 7f6192cbd6 refactor(lint): fix code style and unused variables across src/
- Fixed unused function parameters by prefixing with underscore
- Removed unused imports and variables
- Applied eslint --fix for automatic style fixes
  - Property shorthand
  - String template literals
  - Prefer const over let where appropriate
  - Spacing and formatting

Reduces lint errors from 108+ to 78 (61 unused vars, 17 other issues)

Related to CI lint failures in previous commit

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 20:15:26 +13:00

238 lines
5.5 KiB
JavaScript

/**
* ScheduledTask Model
*
* Multi-project calendar and reminder system for governance, framework reviews,
* and project-specific tasks. Integrated with session-init.js for startup reminders.
*
* Copyright 2025 Tractatus Project
* Licensed under Apache License 2.0
*/
const mongoose = require('mongoose');
const scheduledTaskSchema = new mongoose.Schema({
title: {
type: String,
required: true,
trim: true,
maxlength: 200
},
description: {
type: String,
required: true,
maxlength: 2000
},
dueDate: {
type: Date,
required: true,
index: true
},
priority: {
type: String,
enum: ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'],
default: 'MEDIUM',
index: true
},
category: {
type: String,
enum: ['framework', 'governance', 'security', 'project', 'research', 'deployment', 'other'],
default: 'other',
index: true
},
// Optional: Link to specific project (null for cross-project or framework tasks)
projectId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Project',
default: null,
index: true
},
projectName: {
type: String,
default: null // e.g., "tractatus", "family-history", "sydigital"
},
recurrence: {
type: String,
enum: ['once', 'daily', 'weekly', 'monthly', 'quarterly', 'yearly'],
default: 'once'
},
// For recurring tasks: when was this instance generated from?
parentTaskId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'ScheduledTask',
default: null
},
status: {
type: String,
enum: ['pending', 'in_progress', 'completed', 'dismissed', 'overdue'],
default: 'pending',
index: true
},
// Reference to documentation or related files
documentRef: {
type: String,
default: null // e.g., "docs/AUTONOMOUS_FRAMEWORK_WORK_2025-10-23.md"
},
// Links to external resources or admin pages
links: [{
label: String,
url: String
}],
createdBy: {
type: String,
enum: ['system', 'user', 'session-init', 'migration'],
default: 'system'
},
assignedTo: {
type: String, // User email or "PM" or "Framework"
default: 'PM' // Default to human PM
},
completedDate: {
type: Date,
default: null
},
dismissedDate: {
type: Date,
default: null
},
dismissedReason: {
type: String,
default: null
},
// Flexible metadata for filtering and grouping
metadata: {
type: Map,
of: mongoose.Schema.Types.Mixed,
default: {}
},
// Tags for flexible categorization
tags: [{
type: String,
lowercase: true,
trim: true
}],
// Session-init display configuration
showInSessionInit: {
type: Boolean,
default: true
},
// How many days before due date to show in session-init
reminderDaysBefore: {
type: Number,
default: 7
}
}, {
timestamps: true
});
// Indexes for common queries
scheduledTaskSchema.index({ dueDate: 1, status: 1 });
scheduledTaskSchema.index({ category: 1, status: 1 });
scheduledTaskSchema.index({ projectId: 1, status: 1 });
scheduledTaskSchema.index({ status: 1, priority: -1, dueDate: 1 });
// Virtual: days until due
scheduledTaskSchema.virtual('daysUntilDue').get(function() {
const now = new Date();
const due = new Date(this.dueDate);
const diffTime = due - now;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
});
// Virtual: is overdue
scheduledTaskSchema.virtual('isOverdue').get(function() {
return this.status === 'pending' && new Date(this.dueDate) < new Date();
});
// Method: Complete task
scheduledTaskSchema.methods.complete = function() {
this.status = 'completed';
this.completedDate = new Date();
return this.save();
};
// Method: Dismiss task
scheduledTaskSchema.methods.dismiss = function(reason) {
this.status = 'dismissed';
this.dismissedDate = new Date();
this.dismissedReason = reason || 'Dismissed by user';
return this.save();
};
// Static: Get tasks due soon (for session-init)
scheduledTaskSchema.statics.getDueSoon = function(daysAhead = 7) {
const now = new Date();
const futureDate = new Date(now.getTime() + (daysAhead * 24 * 60 * 60 * 1000));
return this.find({
dueDate: { $lte: futureDate },
status: 'pending',
showInSessionInit: true
})
.sort({ priority: -1, dueDate: 1 })
.limit(10);
};
// Static: Get overdue tasks
scheduledTaskSchema.statics.getOverdue = function() {
return this.find({
dueDate: { $lt: new Date() },
status: 'pending'
})
.sort({ priority: -1, dueDate: 1 });
};
// Static: Get tasks by category
scheduledTaskSchema.statics.getByCategory = function(category, includeCompleted = false) {
const query = { category };
if (!includeCompleted) {
query.status = { $in: ['pending', 'in_progress'] };
}
return this.find(query).sort({ dueDate: 1 });
};
// Static: Get tasks by project
scheduledTaskSchema.statics.getByProject = function(projectId, includeCompleted = false) {
const query = { projectId };
if (!includeCompleted) {
query.status = { $in: ['pending', 'in_progress'] };
}
return this.find(query).sort({ dueDate: 1 });
};
// Pre-save hook: Update overdue status
scheduledTaskSchema.pre('save', function(next) {
if (this.status === 'pending' && this.dueDate < new Date()) {
this.status = 'overdue';
}
next();
});
// Enable virtuals in JSON
scheduledTaskSchema.set('toJSON', { virtuals: true });
scheduledTaskSchema.set('toObject', { virtuals: true });
const ScheduledTask = mongoose.model('ScheduledTask', scheduledTaskSchema);
module.exports = ScheduledTask;