diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index dcce7d9..df497ff 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -117,14 +117,14 @@ destructive remediation gated behind explicit human approval. (LiveLink supplies the ticket ID as dynamic content, not the internal campaign UUID), authenticated via the existing Better Auth session only — no separate token or query-param auth scheme -- [ ] **REVIEW-02**: The page displays the campaign's timeline — linked +- [x] **REVIEW-02**: The page displays the campaign's timeline — linked reports, classification history, and audit events (classify/approve/ remediate/mark-false-positive) — in chronological order - [ ] **REVIEW-03**: The page displays the gathered evidence — parsed EML headers/URLs/attachments, sanitized body preview, and Mimecast blast-radius data (including an explicit `unavailable` state when Mimecast isn't configured) — never rendering a raw/unsanitized body or unredacted secrets -- [ ] **REVIEW-04**: The page displays the current classification (SPAM/ +- [x] **REVIEW-04**: The page displays the current classification (SPAM/ UNWANTED/THREAT), confidence, reasons, and recommended remediation action(s) - [ ] **REVIEW-05**: An operator can approve, remediate, or mark a campaign as @@ -204,9 +204,9 @@ Populated during roadmap creation. | NOTE-01 | Phase 21 | Complete | | ACCESS-01 | Phase 18 | Complete | | REVIEW-01 | Phase 22 | Pending | -| REVIEW-02 | Phase 22 | Pending | +| REVIEW-02 | Phase 22 | Complete | | REVIEW-03 | Phase 22 | Pending | -| REVIEW-04 | Phase 22 | Pending | +| REVIEW-04 | Phase 22 | Complete | | REVIEW-05 | Phase 22 | Pending | | REVIEW-06 | Phase 22 | Pending | diff --git a/.planning/phases/22-approval-ui-livelink-addressable-campaign-review-and-approve/22-04-SUMMARY.md b/.planning/phases/22-approval-ui-livelink-addressable-campaign-review-and-approve/22-04-SUMMARY.md new file mode 100644 index 0000000..8afbbf7 --- /dev/null +++ b/.planning/phases/22-approval-ui-livelink-addressable-campaign-review-and-approve/22-04-SUMMARY.md @@ -0,0 +1,98 @@ +--- +phase: 22-approval-ui-livelink-addressable-campaign-review-and-approve +plan: 04 +subsystem: ui +tags: [react, nextjs, shadcn, phishing, tailwind, lucide] + +# Dependency graph +requires: + - phase: 22-01/02/03 + provides: campaign detail data shape (classification + timeline arrays) these components render +provides: + - "ClassificationCard — read-only latest-verdict display with Reclassify action (REVIEW-04)" + - "TimelineCard — chronological merged-event renderer (REVIEW-02)" +affects: [22-05, 22-06] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "CardTitle className=\"font-bold\" override for the 700-weight card heading (UI-SPEC Typography contract)" + - "Client-side hasPermission(role, 'phishing', ) gate via useSession(), hiding (not disabling) the affordance" + - "Null-classification early-return guard — page-level empty states (plan 06) own the replacement UI, not the card" + +key-files: + created: + - components/phishing/classification-card.tsx + - components/phishing/timeline-card.tsx + modified: [] + +key-decisions: + - "TimelineCard defines its own local TimelineEntry union (per plan's fallback instruction) rather than importing from plan 02, since plan 04 has no depends_on and plan 02's extended detail route may not exist in this worktree yet." + - "Audit event_type 'campaign_classified' is rendered with the same Sparkles/verdict-tinted treatment as 'classification' kind entries (per the plan's note: \"campaign_classified → classification entries\"), distinct from the generic humanized fallback used for any other/future event_type." + - "remediation_approved action count derived defensively from payload.actionIds.length, falling back to payload.actions.length, then 0 — matches the two audit-payload shapes actually written by lib/services/remediation-service.ts." + +patterns-established: + - "Timeline rail: 8px h-2 w-2 rounded-full dot + 1px border-l connector, built with plain divs/Tailwind (UI-SPEC explicitly calls this a one-off, not a new primitive)." + +requirements-completed: [REVIEW-02, REVIEW-04] + +# Metrics +duration: 12min +completed: 2026-07-16 +--- + +# Phase 22 Plan 04: ClassificationCard + TimelineCard Summary + +**Two read-only presentational components — ClassificationCard (verdict/confidence/reasons/action-chips + approval warning, Reclassify gated on `phishing:analyze`) and TimelineCard (chronological reports+classifications+audit-events merge) — built per the UI-SPEC color/typography contract with zero new dependencies.** + +## Performance + +- **Duration:** ~12 min +- **Started:** 2026-07-16T18:18:00Z +- **Completed:** 2026-07-16T18:29:48Z +- **Tasks:** 2/2 completed +- **Files modified:** 2 created + +## Accomplishments +- `ClassificationCard` renders the latest classification's verdict badge, confidence, summary, reasons list, and informational recommended-action chips; shows an amber `Alert` when `requiresApproval` is true; hides (not disables) the Reclassify button unless the session role has `phishing:analyze`; returns `null` when `classification` is missing so the review page's empty states (plan 06) own that surface. +- `TimelineCard` merges `report` / `classification` / `audit` timeline entries into a single ascending vertical list (relies on server ordering, never calls `.sort()`), with a per-kind icon/label/tint mapping including the full `audit_events.event_type` table from the UI-SPEC (`remediation_approved`, `remediation_completed`, `campaign_marked_false_positive`, `campaign_classified`, and a humanized fallback for anything else). + +## Task Commits + +1. **Task 1: ClassificationCard (REVIEW-04)** - `14adddf` (feat) +2. **Task 2: TimelineCard (REVIEW-02)** - `e990a32` (feat) + +**Plan metadata:** commit pending (this SUMMARY + REQUIREMENTS) + +## Files Created/Modified +- `components/phishing/classification-card.tsx` - `ClassificationCard({ campaignId, classification, onReclassified })` — verdict `StatusBadge`, confidence, summary, reasons `