Skip to content

feat: auto-log deal lifecycle events to activity timeline#53

Open
Rishavraaj wants to merge 6 commits intomainfrom
feat/deal-activity-events
Open

feat: auto-log deal lifecycle events to activity timeline#53
Rishavraaj wants to merge 6 commits intomainfrom
feat/deal-activity-events

Conversation

@Rishavraaj
Copy link
Contributor

@Rishavraaj Rishavraaj commented Mar 20, 2026

Summary

Enhances the deal activity timeline by automatically logging system events
whenever deal state changes — previously only manual comments were tracked.

Backend

  • Inject ActivityService into DealsService and wire it up in the backend
    module factory (sales.module.ts)
  • Add optional actorId parameter to all mutating deal service methods so
    events are attributed to the acting user
  • Log the following events automatically:
    • deal_created — on deal creation

    • stage_change — when the deal stage changes (stores from/to values)

    • field_update — when title, value, probability, expected close date, or
      priority changes (stores field name, old and new value)

    • deal_closed — when actualCloseDate is set for the first time (stores
      outcome: won/lost and optional lost reason)

    • company_linked / company_unlinked — when a company is added or removed

    • contact_linked / contact_unlinked — when a contact is added or removed

      (with optional role)

    • owner_assigned / owner_removed — when an owner is added or removed

  • Update addOwner and removeOwner in DealsRepository to include user
    data so the owner's name is available for activity metadata
  • Pass authenticated user ID as actorId from the controller via @Req()

Frontend

  • Add renderSystemEventText() helper in ActivityTimeline that maps each
    event type to a human-readable description
  • Format field names (camelCase → readable label) and date values (ISO →
    "Mar 27, 2026") for display
  • When a field had no previous value, show "set X to Y" instead of
    "updated X from null to Y"
  • Render system events in italic muted text, distinct from comment content

No database schema changes — the existing Activity model's activityType
and metadata fields support all new event types.

Screenshot

image

Test plan

  • Create a deal → timeline shows "created this deal"
  • Change stage → timeline shows "moved deal from Prospecting to Closed
    Won"
  • Set expected close date for first time → shows "set expected close date
    to Mar 27, 2026"
  • Update an existing date → shows "updated expected close date from X to
    Y"
  • Set actualCloseDate with closed_won stage → shows "marked deal as
    Won"
  • Set actualCloseDate with closed_lost + lost reason → shows "marked
    deal as Lost: "
  • Link a company → shows "linked company Acme Corp"
  • Remove a company → shows "unlinked company Acme Corp"
  • Link a contact with a role → shows "linked contact John Doe as Decision
    Maker"
  • Remove a contact → shows "unlinked contact John Doe"
  • Add an owner → shows "assigned Jane Smith as owner"
  • Remove an owner → shows "removed Jane Smith as owner"
  • Existing comment create/edit/delete still works unchanged

Rishavraaj and others added 3 commits March 20, 2026 16:28
- Inject ActivityService into DealsService and wire up the backend module factory
- Log deal_created, stage_change, field_update, deal_closed, company_linked/unlinked, contact_linked/unlinked, owner_assigned/removed events automatically
- Include user data in addOwner/removeOwner repository responses for activity metadata
- Pass authenticated actorId from controller to service for all mutating operations
- Render system events as human-readable descriptions in ActivityTimeline with formatted field names and date values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- libs/sales: DealsService unit tests asserting activityService.create
  is called with correct event type and metadata for deal_created,
  stage_change, deal_closed, field_update, company_linked/unlinked,
  contact_linked/unlinked, owner_assigned/removed
- apps/web: ActivityTimeline vitest unit tests verifying each system
  event type renders the correct text in the UI
- apps/web-e2e: Playwright e2e tests verifying system events appear in
  the activity timeline after create, stage edit, and company/contact
  add/remove actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rishavraaj Rishavraaj force-pushed the feat/deal-activity-events branch from 56effa9 to 61e1560 Compare March 20, 2026 11:28
Rishavraaj and others added 2 commits March 20, 2026 17:03
Remove unused BadRequestException/NotFoundException imports and add
required organizationId field to CreateDealInput test fixtures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both methods take req as their first argument (for actorId). The tests
were missing it, causing dto to be undefined at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rishavraaj Rishavraaj self-assigned this Mar 20, 2026
/Activity/i matched both the deal title and the section heading,
causing a strict mode violation. Switching to exact: true targets
only the <h2>Activity</h2> heading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant