chore: estructura inicial del MVP

Backend (Express + MariaDB) y frontend (React + Vite, identidad Fluent/Windows) con el
nucleo funcional: seguridad, organizacion, proyectos, actividades, subtareas, dependencias,
dashboard, calendario, gantt, comentarios, adjuntos, notificaciones in-app y catalogos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-09-03 08:37:58 -05:00
commit 1d22adc42e
135 changed files with 10913 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
import { pool } from '../config/db.js';
export async function logAudit({ userId, action, entityType, entityId, detail }) {
await pool.query(
`INSERT INTO audit_log (user_id, action, entity_type, entity_id, detail_json) VALUES (?, ?, ?, ?, ?)`,
[userId, action, entityType, entityId ?? null, detail ? JSON.stringify(detail) : null]
);
}
+4
View File
@@ -0,0 +1,4 @@
// Genera codigos legibles tipo PRY-0007 / ACT-0042 a partir del ultimo id insertado.
export function buildCode(prefix, id) {
return `${prefix}-${String(id).padStart(4, '0')}`;
}
+19
View File
@@ -0,0 +1,19 @@
// Estado de vencimiento calculado al vuelo (no se guarda en BD).
// Reglas del SPEC: vence en >3 dias = normal, <=3 dias = advertencia, hoy = urgente, vencido = critico.
export function dueStatus(dueDate, isDone = false) {
if (!dueDate || isDone) return 'none';
const today = new Date();
today.setHours(0, 0, 0, 0);
const due = new Date(dueDate);
due.setHours(0, 0, 0, 0);
const diffDays = Math.round((due - today) / 86400000);
if (diffDays < 0) return 'overdue';
if (diffDays === 0) return 'today';
if (diffDays <= 3) return 'warning';
return 'on_time';
}
export function todayMysql() {
return new Date().toISOString().slice(0, 10);
}
+18
View File
@@ -0,0 +1,18 @@
export function ok(res, data = null, status = 200) {
return res.status(status).json({ success: true, data, error: null });
}
export function fail(res, status, message) {
return res.status(status).json({ success: false, data: null, error: message });
}
export class HttpError extends Error {
constructor(status, message) {
super(message);
this.status = status;
}
}
export function asyncHandler(fn) {
return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
}