feat: activity timeline API and component (#181)#299
feat: activity timeline API and component (#181)#299rubenvdlinde wants to merge 15 commits intodevelopmentfrom
Conversation
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 249/249 | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ |
Spec coverage: 14% (42 tests / 298 specs)
Quality workflow — 2026-04-20 19:12 UTC
Download the full PDF report from the workflow artifacts.
| } | ||
|
|
||
| // Build query filters. | ||
| $filterParams = ['channel' => 'worklog']; |
There was a problem hiding this comment.
[unfixed: in-container edit blocked — files owned by root, no sudo; remediation described below] Rule: OWASP A01:2021 (Broken Access Control / CWE-284) — getWorklog() with an unsupported entityType (e.g. lead, contact, or any arbitrary string) silently omits the entity filter and passes only ['channel' => 'worklog'] to objectService->findObjects(). This causes the endpoint to return ALL worklog entries in the system rather than the intended entity-scoped subset. Any authenticated user can trigger this by passing entityType=lead&entityId=<any-uuid>. Fix: add an early return for unsupported entity types before building $filterParams:
if ($entityType !== 'client' && $entityType !== 'request') {
return [
'items' => [], 'total' => 0,
'page' => 1, 'pages' => 0, 'totalDuration' => 'PT0S',
];
}| $date = $this->request->getParam('date', ''); | ||
|
|
||
| // Validate required fields. | ||
| if ($entityType === '' || $entityId === '' || $duration === '') { |
There was a problem hiding this comment.
[unfixed: in-container edit blocked — files owned by root, no sudo; remediation described below] Rule: OWASP A04:2021 (Insecure Design / CWE-20) — createWorklog() validates that entityType is non-empty but does not enforce that it is one of the supported values (client or request). Passing entityType=lead or entityType=contact results in a worklog contactmoment being persisted without any entity reference (client/request field both absent), creating an orphaned record that cannot be retrieved via the intended worklog API. Fix: extend the existing validation block to whitelist the supported entity types:
$allowedEntityTypes = ['client', 'request'];
if ($entityType === '' || $entityId === '' || $duration === '' || !in_array($entityType, $allowedEntityTypes, true)) {
return new JSONResponse(['message' => 'Missing required fields'], 400);
}| this.totalPages = response.data.pages || 1 | ||
| } catch (error) { | ||
| this.error = t('pipelinq', 'Failed to load activities') | ||
| console.error('Failed to fetch timeline:', error) |
There was a problem hiding this comment.
[unfixed: suggestion only — no blocking risk] Rule: OWASP A09:2021 (Security Logging / CWE-532) — console.error('Failed to fetch timeline:', error) logs the full axios error object to the browser console, including request config (URL with entityType and entityId query params), response headers, and body. Visible only to the authenticated user's own browser session, so the risk is low. Consider: console.error('Failed to fetch timeline') without the full error object to reduce verbose client-side logging in production.
Security Review — Clyde BarcodeResult: FAIL (0 fixed, 1 WARNING unfixed, 2 SUGGESTIONS unfixed, 1 blocking) Checks run
Checks skipped: Findings[WARNING] OWASP A01:2021 — [SUGGESTION] OWASP A04:2021 — [SUGGESTION] OWASP A09:2021 — npm audit drift notePre-run quality stage reported Positive findings
Verdict: FAIL — 1 unfixed WARNING ( |
Closes #181
Summary
Implements a unified activity timeline API and Vue component for Pipelinq, aggregating interactions from contactmomenten, tasks, emails, and calendar events. The feature enables users to view CRM activity for clients, requests, leads, and contacts in a consolidated timeline view. Includes worklog tracking functionality for manual time logging.
Spec Reference
openspec/changes/activity-timeline/design.mdChanges
lib/Service/ActivityTimelineService.php— Activity timeline aggregation service with support for multiple data sources (contactmoment, task, emailLink, calendarLink)lib/Controller/ActivityTimelineController.php— REST API controller for timeline and worklog endpoints (/api/timeline,/api/worklog)src/components/ActivityTimeline.vue— Vue component for displaying activity timeline with filtering by activity type and paginationappinfo/routes.php— Added three routes for timeline GET, worklog GET, and worklog POSTsrc/views/clients/ClientDetail.vue— Integrated ActivityTimeline component in client detail pagesrc/views/leads/LeadDetail.vue— Integrated ActivityTimeline component in lead detail pagesrc/views/requests/RequestDetail.vue— Integrated ActivityTimeline component in request detail pageTest Coverage
Notes
contactmoment,task,emailLink, andcalendarLinkschemascontactmomentobjects withchannel='worklog'