/*********************************************************************************************************************************************************************** * File Name: task_completion.mdl.js * Type of Program: Model * Description: Sequelize models for `task_completions` and `task_completion_files`. * A completion is created when a user turns in work for a task. * Multiple completions are allowed (resubmit anytime). * Files are stored separately — one completion can have many files. * * Author: Kenneth Obsequio (@lash0000) * Date Created: Jun. 13, 2026 ***********************************************************************************************************************************************************************/ const { DataTypes } = require('sequelize'); const sequelize = require('../../config/db.config'); const mdl_Users = require('../users/users.mdl'); const { Task } = require('./task.mdl'); // ─── TaskCompletion ──────────────────────────────────────────────────────────── const TaskCompletion = sequelize.define('TaskCompletion', { completion_id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, order: 3, }, task_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'tasks', key: 'task_id' }, onDelete: 'CASCADE', order: 4, }, user_id: { type: DataTypes.BIGINT, allowNull: false, references: { model: 'users', key: 'user_id' }, onDelete: 'CASCADE', order: 5, }, note: { type: DataTypes.TEXT, allowNull: true, comment: 'Optional note the user attaches when submitting.', order: 1, }, submitted_at: { type: DataTypes.DATE, defaultValue: DataTypes.NOW, allowNull: false, order: 2, }, // ── Audit trails ──────────────────────────────────────────────────────── createdBy: { type: DataTypes.BIGINT, allowNull: true, order: 6 }, updatedBy: { type: DataTypes.BIGINT, allowNull: true, order: 7 }, deletedBy: { type: DataTypes.BIGINT, allowNull: true, order: 8 }, }, { tableName: 'task_completions', paranoid: true, timestamps: true, indexes: [ { fields: ['task_id'], name: 'idx_tc_task_id' }, { fields: ['user_id'], name: 'idx_tc_user_id' }, { fields: ['task_id', 'user_id'], name: 'idx_tc_task_user' }, ], }); // ─── TaskCompletionFile ──────────────────────────────────────────────────────── const TaskCompletionFile = sequelize.define('TaskCompletionFile', { file_id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, }, completion_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'task_completions', key: 'completion_id' }, onDelete: 'CASCADE', }, file_url: { type: DataTypes.STRING, allowNull: false, comment: 'Storage path or CDN URL of the uploaded file.', }, file_name: { type: DataTypes.STRING, allowNull: false, comment: 'Original filename as uploaded by the user.', }, file_size: { type: DataTypes.INTEGER, allowNull: true, comment: 'File size in bytes.', }, mime_type: { type: DataTypes.STRING, allowNull: true, comment: 'MIME type e.g. application/pdf, image/png.', }, storage_key: { type: DataTypes.STRING(500), allowNull: true, comment: 'S3 object key (e.g. "images/uuid.jpg"), used by the download proxy endpoint.', }, // ── Audit trails ──────────────────────────────────────────────────────── createdBy: { type: DataTypes.BIGINT, allowNull: true }, updatedBy: { type: DataTypes.BIGINT, allowNull: true }, deletedBy: { type: DataTypes.BIGINT, allowNull: true }, }, { tableName: 'task_completion_files', paranoid: true, timestamps: true, indexes: [ { fields: ['completion_id'], name: 'idx_tcf_completion_id' }, ], }); // ─── Associations ────────────────────────────────────────────────────────────── Task.hasMany(TaskCompletion, { foreignKey: 'task_id', as: 'completions' }); TaskCompletion.belongsTo(Task, { foreignKey: 'task_id', as: 'task' }); mdl_Users.hasMany(TaskCompletion, { foreignKey: 'user_id', as: 'taskCompletions' }); TaskCompletion.belongsTo(mdl_Users, { foreignKey: 'user_id', as: 'user' }); TaskCompletion.hasMany(TaskCompletionFile, { foreignKey: 'completion_id', as: 'files' }); TaskCompletionFile.belongsTo(TaskCompletion, { foreignKey: 'completion_id', as: 'completion' }); module.exports = { TaskCompletion, TaskCompletionFile };