diff --git a/backend/routes/ivantiFpWorkflow.js b/backend/routes/ivantiFpWorkflow.js
index c788da6..0cc4081 100644
--- a/backend/routes/ivantiFpWorkflow.js
+++ b/backend/routes/ivantiFpWorkflow.js
@@ -124,7 +124,41 @@ const fpUpload = multer({
function createIvantiFpWorkflowRouter(db, requireAuth) {
const router = express.Router();
- // POST /api/ivanti/fp-workflow
+ /**
+ * POST /api/ivanti/fp-workflow
+ *
+ * Creates a False Positive workflow batch in the Ivanti/RiskSense API,
+ * optionally uploads file attachments, records the submission locally,
+ * and marks the associated queue items as complete.
+ *
+ * Content-Type: multipart/form-data
+ *
+ * @param {string} req.body.name - Workflow name (required, max 255 chars)
+ * @param {string} req.body.reason - Reason for the FP determination (required)
+ * @param {string} [req.body.description] - Additional description (optional, max 2000 chars)
+ * @param {string} req.body.expirationDate - ISO date string, must be a future date (required)
+ * @param {string} [req.body.scopeOverride] - "Authorized" (default) or "None"
+ * @param {string} req.body.findingIds - JSON-encoded array of Ivanti finding IDs
+ * @param {string} req.body.queueItemIds - JSON-encoded array of local queue item IDs
+ * @param {File[]} [req.files] - Up to 10 file attachments (max 10 MB each);
+ * allowed extensions: .pdf .png .jpg .jpeg .gif
+ * .doc .docx .xlsx .csv .txt .zip
+ *
+ * @returns {object} 200 - Success
+ * { success: true, workflowBatchId: number, generatedId: string,
+ * attachmentResults: Array<{ filename: string, success: boolean, error?: string }>,
+ * queueItemsUpdated: number, status: 'success' | 'partial' }
+ * @returns {object} 400 - Validation error
+ * { error: string } or { success: false, errors: { [field]: string } }
+ * @returns {object} 403 - Queue item ownership violation
+ * { error: string }
+ * @returns {object} 429 - Ivanti rate limit
+ * { success: false, error: string, step: 'create_workflow' }
+ * @returns {object} 500 - Server configuration error
+ * { success: false, error: string, step: 'create_workflow' }
+ * @returns {object} 502 - Ivanti API error
+ * { success: false, error: string, step: 'create_workflow', details?: string }
+ */
router.post('/', requireAuth(db), requireGroup('Admin', 'Standard_User'), (req, res) => {
fpUpload(req, res, (multerErr) => {
if (multerErr) {
@@ -283,7 +317,7 @@ function createIvantiFpWorkflowRouter(db, requireAuth) {
const failedAttachments = attachmentResults.filter(r => !r.success);
let status = 'success';
if (files.length > 0 && failedAttachments.length > 0) {
- status = failedAttachments.length === files.length ? 'partial' : 'partial';
+ status = 'partial';
}
// 5. Insert submission record
diff --git a/frontend/src/components/pages/ReportingPage.js b/frontend/src/components/pages/ReportingPage.js
index abef486..b61c23e 100644
--- a/frontend/src/components/pages/ReportingPage.js
+++ b/frontend/src/components/pages/ReportingPage.js
@@ -1493,26 +1493,29 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
display: 'flex', gap: '0.5rem',
}}>
{/* Create FP Workflow — visible for editor/admin only */}
- {canWrite && (
-
- )}
+ {canWrite && (() => {
+ const fpEnabled = isCreateFpButtonEnabled(items, selectedIds);
+ return (
+
+ );
+ })()}
{/* Delete selected — only shown when items are selected */}
{selectedIds.size > 0 && (