diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ac2af..6dd9354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This file is the running release and change log for CODEXIUM. Keep it updated wh ### Added +- Project milestones with status, due dates, notes, and edit-time sequencing inside the project workflow +- Project-side milestone and work-order rollups surfaced on project list and detail pages - Inventory SKU master builder with family-level sequence codes, branch-aware taxonomy management, and generated SKU previews on the item form - Thumbnail image attachment staging on inventory item create/edit pages, with upload-on-save and replacement/removal support - Dedicated inventory-item thumbnail display on the item detail page @@ -61,6 +63,7 @@ This file is the running release and change log for CODEXIUM. Keep it updated wh ### Changed +- Project records now persist milestone plans directly on create/edit instead of treating schedule checkpoints as freeform notes only - Company theme colors and font now persist correctly across refresh through startup brand-profile hydration in the frontend theme provider - Demand-planning purchase-order draft generation now links sales-order lines only when the purchase item matches the originating sales item - Admin user edits now normalize blank passwords to null and surface save failures instead of appearing unresponsive diff --git a/README.md b/README.md index 7622d8f..cbb271f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Current foundation scope includes: - branded quote, sales-order, and purchase-order PDFs through the shared backend document pipeline - purchase-order supporting documents for vendor invoices, acknowledgements, certifications, and backup files - shipping shipments linked to sales orders with packing slips, shipping labels, bills of lading, and logistics attachments -- projects with customer/commercial/shipment linkage, owners, due dates, notes, and attachments +- projects with customer/commercial/shipment linkage, owners, due dates, milestones, rollups, notes, and attachments - manufacturing work orders with project linkage, station-based operation templates, material issue posting, completion posting, and work-order attachments - planning gantt timelines with live project and manufacturing schedule data - sales-order demand planning with multi-level BOM explosion, stock/open-supply netting, and build/buy recommendations @@ -63,13 +63,13 @@ Current completed foundation areas: Near-term priorities: -1. Project milestones and project-side rollup visibility +1. Deeper project-side execution visibility, cost/supply rollups, and project cockpit refinement 2. Manufacturing routing/work-center depth, labor capture, and capacity-aware execution views Revisit / deferred items: - local Windows Prisma migration reliability -- project milestones and project-side rollup visibility +- deeper project-side execution visibility, cost/supply rollups, and project cockpit refinement Dashboard direction: @@ -91,7 +91,7 @@ Navigation direction: ## Projects Direction -Projects are now the long-running program and delivery layer for cross-module execution. The current slice ships project records with customer linkage, owner assignment, priority, due dates, notes, commercial document links, shipment links, attachments, and dashboard visibility. +Projects are now the long-running program and delivery layer for cross-module execution. The current slice ships project records with customer linkage, owner assignment, priority, due dates, milestones, project-side milestone/work-order rollups, notes, commercial document links, shipment links, attachments, and dashboard visibility. Current interactions: @@ -99,6 +99,7 @@ Current interactions: - Sales: quotes and sales orders can already attach to projects - Shipping: shipments tied to project deliverables are visible from the project record - Dashboard: projects now contribute status, risk, backlog, and overdue widgets +- Detail/List UX: projects now surface milestone progress and linked execution rollups Next expansion areas: @@ -385,7 +386,7 @@ The current admin operations slice supports: Current follow-up direction: - revision comparison UX for changed sales and purchasing documents -- project milestones and project-side rollup visibility +- deeper project-side execution visibility, cost/supply rollups, and project cockpit refinement ## UI Notes diff --git a/ROADMAP.md b/ROADMAP.md index 0772274..bde4e31 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,7 +14,7 @@ This file tracks work that still needs to be completed. Shipped phase history an ## Near-term priority order -1. Project milestones, project rollups, and deeper project-side execution visibility +1. Deeper project-side execution visibility, cost/supply rollups, and project cockpit refinement 2. Manufacturing routing/work-center depth, labor capture, and capacity-aware execution views 3. Dashboard KPI, alert, recent-activity, and exception-widget expansion 4. Longer-term session history and audit depth beyond the current review filtering and retention cleanup @@ -75,8 +75,8 @@ This file tracks work that still needs to be completed. Shipped phase history an ### Projects and program management - Project document hub for drawings, support files, correspondence, and revision references -- Milestones, checkpoints, and non-manufacturing work packages for long-running execution tracking -- Project-level commercial, material, schedule, and delivery rollups +- Non-manufacturing work packages for long-running execution tracking +- Deeper project-level commercial, material, schedule, and delivery rollups - Cross-functional visibility for engineering, purchasing, manufacturing, shipping, and customer communication - Project templates for repeatable build types - Project-specific attachment bundles and revision snapshots diff --git a/SHIPPED.md b/SHIPPED.md index aaf4e90..a48ae9a 100644 --- a/SHIPPED.md +++ b/SHIPPED.md @@ -33,6 +33,7 @@ This file tracks roadmap phases, slices, and major foundations that have already - Packing-slip, shipping-label, and bill-of-lading PDF rendering for shipments - Logistics attachments directly on shipment records - Projects foundation with customer, quote, sales-order, shipment, owner, due-date, notes, and attachment linkage +- Project milestones and project-side milestone/work-order rollups - Project list/detail/create/edit workflows and dashboard program widgets - Manufacturing foundation with work orders, project linkage, material issue posting, completion posting, and work-order attachments - Manufacturing stations, item routing templates, and automatic work-order operation planning for gantt scheduling @@ -68,7 +69,8 @@ This file tracks roadmap phases, slices, and major foundations that have already ### Phase 5: Projects and program management -- Project records with customer linkage, status, owner, priority, due dates, and notes +- Project records with customer linkage, status, owner, priority, due dates, milestones, and notes +- Project milestone status tracking and project-side milestone/work-order rollups - Project-to-quote, sales-order, and shipment linkage for delivery context - Project attachments through the shared file pipeline - Project list/detail/create/edit flows and dashboard visibility diff --git a/client/src/modules/projects/ProjectDetailPage.tsx b/client/src/modules/projects/ProjectDetailPage.tsx index 8efa63d..031693e 100644 --- a/client/src/modules/projects/ProjectDetailPage.tsx +++ b/client/src/modules/projects/ProjectDetailPage.tsx @@ -8,6 +8,7 @@ import { Link, useParams } from "react-router-dom"; import { FileAttachmentsPanel } from "../../components/FileAttachmentsPanel"; import { useAuth } from "../../auth/AuthProvider"; import { api, ApiError } from "../../lib/api"; +import { projectMilestoneStatusPalette } from "./config"; import { ProjectPriorityBadge } from "./ProjectPriorityBadge"; import { ProjectStatusBadge } from "./ProjectStatusBadge"; @@ -73,6 +74,27 @@ export function ProjectDetailPage() {

Due Date

{project.dueDate ? new Date(project.dueDate).toLocaleDateString() : "Not set"}

Created

{new Date(project.createdAt).toLocaleDateString()}
+
+
+

Milestones

+
{project.rollups.completedMilestoneCount}/{project.rollups.milestoneCount}
+
{project.rollups.openMilestoneCount} open
+
+
+

Overdue Milestones

+
{project.rollups.overdueMilestoneCount}
+
+
+

Linked Work Orders

+
{project.rollups.workOrderCount}
+
{project.rollups.activeWorkOrderCount} active
+
+
+

Overdue Work Orders

+
{project.rollups.overdueWorkOrderCount}
+
{project.rollups.completedWorkOrderCount} complete
+
+

Customer Linkage

@@ -104,6 +126,48 @@ export function ProjectDetailPage() {
+
+
+
+

Milestones

+

Track project checkpoints, blockers, and completion progress.

+
+ {canManage ? ( + + Edit milestones + + ) : null} +
+ {project.milestones.length === 0 ? ( +
+ No milestones are defined for this project yet. +
+ ) : ( +
+ {project.milestones.map((milestone) => ( +
+
+
+
{milestone.title}
+
+ + {milestone.status.replace("_", " ")} + + + Due {milestone.dueDate ? new Date(milestone.dueDate).toLocaleDateString() : "not scheduled"} + + {milestone.completedAt ? ( + Completed {new Date(milestone.completedAt).toLocaleDateString()} + ) : null} +
+ {milestone.notes ?
{milestone.notes}
: null} +
+
+
+ ))} +
+ )} +
{planning ? (

Material Readiness

diff --git a/client/src/modules/projects/ProjectFormPage.tsx b/client/src/modules/projects/ProjectFormPage.tsx index 0e11397..da0e7f1 100644 --- a/client/src/modules/projects/ProjectFormPage.tsx +++ b/client/src/modules/projects/ProjectFormPage.tsx @@ -2,6 +2,7 @@ import type { ProjectCustomerOptionDto, ProjectDocumentOptionDto, ProjectInput, + ProjectMilestoneInput, ProjectOwnerOptionDto, ProjectShipmentOptionDto, } from "@mrp/shared/dist/projects/types.js"; @@ -11,7 +12,7 @@ import { Link, useNavigate, useParams } from "react-router-dom"; import { ConfirmActionDialog } from "../../components/ConfirmActionDialog"; import { useAuth } from "../../auth/AuthProvider"; import { api, ApiError } from "../../lib/api"; -import { emptyProjectInput, projectPriorityOptions, projectStatusOptions } from "./config"; +import { emptyProjectInput, projectMilestoneStatusOptions, projectPriorityOptions, projectStatusOptions } from "./config"; type ProjectPendingConfirmation = | { kind: "change-customer"; customerId: string; customerName: string } @@ -43,6 +44,13 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) { const [isSaving, setIsSaving] = useState(false); const [pendingConfirmation, setPendingConfirmation] = useState(null); + function reindexMilestones(milestones: ProjectMilestoneInput[]) { + return milestones.map((milestone, index) => ({ + ...milestone, + sortOrder: index * 10, + })); + } + useEffect(() => { if (!token) { return; @@ -83,6 +91,14 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) { ownerId: project.ownerId, dueDate: project.dueDate, notes: project.notes, + milestones: project.milestones.map((milestone) => ({ + id: milestone.id, + title: milestone.title, + status: milestone.status, + dueDate: milestone.dueDate, + notes: milestone.notes, + sortOrder: milestone.sortOrder, + })), }); setCustomerSearchTerm(project.customerName); setOwnerSearchTerm(project.ownerName ?? ""); @@ -162,6 +178,44 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) { setShipmentSearchTerm(selectedShipment?.shipmentNumber ?? ""); } + function addMilestone() { + setForm((current) => ({ + ...current, + milestones: reindexMilestones([ + ...current.milestones, + { + id: null, + title: "", + status: "PLANNED", + dueDate: current.dueDate, + notes: "", + sortOrder: current.milestones.length * 10, + }, + ]), + })); + } + + function updateMilestone(index: number, key: Key, value: ProjectMilestoneInput[Key]) { + setForm((current) => ({ + ...current, + milestones: current.milestones.map((milestone, milestoneIndex) => + milestoneIndex === index + ? { + ...milestone, + [key]: value, + } + : milestone + ), + })); + } + + function removeMilestone(index: number) { + setForm((current) => ({ + ...current, + milestones: reindexMilestones(current.milestones.filter((_, milestoneIndex) => milestoneIndex !== index)), + })); + } + async function handleSubmit(event: React.FormEvent) { event.preventDefault(); if (!token) { @@ -477,6 +531,76 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) { Notes