adpa-enterprise-framework-automation
Version:
Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe
332 lines • 11.6 kB
JavaScript
// Project Controller
// filepath: src/api/controllers/ProjectController.ts
import { Project } from '../../models/Project.js';
import { logger } from '../../utils/logger.js';
import { validationResult } from 'express-validator';
export class ProjectController {
/**
* Get all projects with optional filtering and pagination
*/
static async getAllProjects(req, res) {
try {
const { page = 1, limit = 10, status, framework, owner, search, sortBy = 'updatedAt', sortOrder = 'desc' } = req.query;
// Build filter object
const filter = {};
if (status)
filter.status = status;
if (framework)
filter.framework = framework;
if (owner)
filter.owner = new RegExp(owner, 'i');
if (search) {
filter.$or = [
{ name: new RegExp(search, 'i') },
{ description: new RegExp(search, 'i') }
];
}
// Calculate pagination
const pageNum = parseInt(page);
const limitNum = parseInt(limit);
const skip = (pageNum - 1) * limitNum;
// Build sort object
const sort = {};
sort[sortBy] = sortOrder === 'desc' ? -1 : 1;
// Execute query
const [projects, total] = await Promise.all([
Project.find(filter)
.sort(sort)
.skip(skip)
.limit(limitNum)
.lean(),
Project.countDocuments(filter)
]);
// Calculate pagination info
const totalPages = Math.ceil(total / limitNum);
const hasNextPage = pageNum < totalPages;
const hasPrevPage = pageNum > 1;
res.json({
success: true,
data: projects,
pagination: {
currentPage: pageNum,
totalPages,
totalItems: total,
itemsPerPage: limitNum,
hasNextPage,
hasPrevPage
},
filters: {
status,
framework,
owner,
search
}
});
logger.info(`📊 Retrieved ${projects.length} projects (page ${pageNum}/${totalPages})`);
}
catch (error) {
logger.error('❌ Error retrieving projects:', error);
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to retrieve projects'
});
}
}
/**
* Get a single project by ID
*/
static async getProjectById(req, res) {
try {
const { id } = req.params;
const project = await Project.findById(id).lean();
if (!project) {
res.status(404).json({
success: false,
error: 'Not Found',
message: 'Project not found'
});
return;
}
res.json({
success: true,
data: project
});
logger.info(`📊 Retrieved project: ${project.name} (${id})`);
}
catch (error) {
logger.error('❌ Error retrieving project:', error);
if (error.name === 'CastError') {
res.status(400).json({
success: false,
error: 'Bad Request',
message: 'Invalid project ID format'
});
return;
}
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to retrieve project'
});
}
}
/**
* Create a new project
*/
static async createProject(req, res) {
try {
// Check for validation errors
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.status(400).json({
success: false,
error: 'Validation Error',
message: 'Invalid input data',
details: errors.array()
});
return;
}
const projectData = req.body;
// Create new project
const project = new Project(projectData);
const savedProject = await project.save();
res.status(201).json({
success: true,
data: savedProject,
message: 'Project created successfully'
});
logger.info(`✅ Created new project: ${savedProject.name} (${savedProject._id})`);
}
catch (error) {
logger.error('❌ Error creating project:', error);
if (error.name === 'ValidationError') {
res.status(400).json({
success: false,
error: 'Validation Error',
message: 'Invalid project data',
details: error.errors
});
return;
}
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to create project'
});
}
}
/**
* Update an existing project
*/
static async updateProject(req, res) {
try {
// Check for validation errors
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.status(400).json({
success: false,
error: 'Validation Error',
message: 'Invalid input data',
details: errors.array()
});
return;
}
const { id } = req.params;
const updateData = req.body;
const project = await Project.findByIdAndUpdate(id, updateData, { new: true, runValidators: true });
if (!project) {
res.status(404).json({
success: false,
error: 'Not Found',
message: 'Project not found'
});
return;
}
res.json({
success: true,
data: project,
message: 'Project updated successfully'
});
logger.info(`✅ Updated project: ${project.name} (${id})`);
}
catch (error) {
logger.error('❌ Error updating project:', error);
if (error.name === 'CastError') {
res.status(400).json({
success: false,
error: 'Bad Request',
message: 'Invalid project ID format'
});
return;
}
if (error.name === 'ValidationError') {
res.status(400).json({
success: false,
error: 'Validation Error',
message: 'Invalid project data',
details: error.errors
});
return;
}
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to update project'
});
}
}
/**
* Delete a project
*/
static async deleteProject(req, res) {
try {
const { id } = req.params;
const project = await Project.findByIdAndDelete(id);
if (!project) {
res.status(404).json({
success: false,
error: 'Not Found',
message: 'Project not found'
});
return;
}
res.json({
success: true,
message: 'Project deleted successfully',
data: { id: project._id, name: project.name }
});
logger.info(`🗑️ Deleted project: ${project.name} (${id})`);
}
catch (error) {
logger.error('❌ Error deleting project:', error);
if (error.name === 'CastError') {
res.status(400).json({
success: false,
error: 'Bad Request',
message: 'Invalid project ID format'
});
return;
}
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to delete project'
});
}
}
/**
* Get project statistics
*/
static async getProjectStats(req, res) {
try {
const stats = await Project.aggregate([
{
$group: {
_id: null,
totalProjects: { $sum: 1 },
averageComplianceScore: { $avg: '$complianceScore' },
totalDocuments: { $sum: '$documents' },
totalStakeholders: { $sum: '$stakeholders' }
}
},
{
$project: {
_id: 0,
totalProjects: 1,
averageComplianceScore: { $round: ['$averageComplianceScore', 2] },
totalDocuments: 1,
totalStakeholders: 1
}
}
]);
const statusStats = await Project.aggregate([
{
$group: {
_id: '$status',
count: { $sum: 1 }
}
}
]);
const frameworkStats = await Project.aggregate([
{
$group: {
_id: '$framework',
count: { $sum: 1 },
averageCompliance: { $avg: '$complianceScore' }
}
},
{
$project: {
_id: 1,
count: 1,
averageCompliance: { $round: ['$averageCompliance', 2] }
}
}
]);
res.json({
success: true,
data: {
overview: stats[0] || {
totalProjects: 0,
averageComplianceScore: 0,
totalDocuments: 0,
totalStakeholders: 0
},
statusBreakdown: statusStats,
frameworkBreakdown: frameworkStats
}
});
logger.info('📊 Retrieved project statistics');
}
catch (error) {
logger.error('❌ Error retrieving project statistics:', error);
res.status(500).json({
success: false,
error: 'Internal server error',
message: 'Failed to retrieve project statistics'
});
}
}
}
//# sourceMappingURL=ProjectController.js.map