---
id: WF-CRM-ACT-001
title: 'Log an activity with its links, files and follow-up'
trigger: >-
  A user logs an interaction from a record screen, or an import or integration requests
  activity creation.
product_area: crm
module: activities-tasks
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-CRM-ACT-001
  - CAP-CRM-ACT-002
  - CAP-CRM-ACT-004
  - CAP-CRM-ACT-006
moves:
  - STATE-CRM-ACT-001
  - STATE-CRM-ACT-002
  - STATE-CRM-ACT-004
crosses:
  - SVC-CRM-ACT-activities
  - SVC-CRM-ACT-tasks
idempotency: >-
  The sheet chooses its creation identifier before sending. While the row exists, a
  matching request digest returns the saved interaction before file preparation or another
  follow-up, and a different digest conflicts. Concurrent copies converge through the
  primary key. Imports instead use source matching without the console digest.
concurrency: >-
  Distinct creations use distinct identifiers. Concurrent deliveries of the same creation
  converge on one stored row after the key conflict resolves. The optional follow-up
  shares the interaction transaction.
hops:
  - 'n': 1
    actor_or_service: Activity entry sheet
    action: >-
      Validate the entry, calculate any chosen follow-up interval from the browser
      calendar, and send using the sheet’s retained identifier.
    anchor: 'react-console:components/activities/log-activity-sheet.tsx:LogActivitySheet'
    seam: sync
    on_failure: >-
      Show field failures; recover an ambiguous response through repeat-safe creation and
      a read of the chosen identifier.
    left_inconsistent: A save may already have committed despite a lost response.
    observer: The user sees validation or save feedback.
    provenance: test
    source: >-
      react-console:lib/activities/retry-safe-writes.test.ts#answers a lost response with
      the activity it logged, and logs no second one;
      react-console:components/activities/log-activity-sheet.tsx:LogActivitySheet
  - 'n': 2
    actor_or_service: Activities API
    action: >-
      Authorize interaction creation and, when requested, task creation; reject extra body
      properties and compute the request digest.
    anchor: 'services-crm:modules/activities/aws/api/activities.routes.ts:activitiesRoutes'
    seam: sync
    on_failure: Return a validation or authorization refusal before persistence.
    left_inconsistent: No record change has begun.
    observer: The requesting caller receives the response.
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a follow-up
      task to a caller without crm.tasks.create: 403
  - 'n': 3
    actor_or_service: Activity creation replay check
    action: >-
      Check an existing creation identifier and return a digest match or reject a
      different request.
    anchor: >-
      services-crm:modules/activities/services/persistence/activities.ts:replayActivityCreate
    seam: sync
    on_failure: Return a conflict for differing creation content.
    left_inconsistent: The existing record is retained unchanged.
    observer: The caller receives the saved interaction or conflict.
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#makes
      one follow-up task
  - 'n': 4
    actor_or_service: Shared file preparation
    action: >-
      Prepare permanent copies of newly supplied supporting files before starting the
      record transaction.
    anchor: 'services-crm:modules/activities/services/persistence/activities.ts:saveNewActivity'
    seam: sync
    on_failure: Refuse creation if file preparation fails.
    left_inconsistent: >-
      Unreferenced prepared copies can remain for shared cleanup; completion timing is
      outside local proof.
    observer: Shared asset processing records expose the preparation outcome.
    provenance: observed
    source: 'services-crm:modules/activities/services/persistence/activities.ts:saveNewActivity'
  - 'n': 5
    actor_or_service: Activity persistence transaction
    action: >-
      Within one transaction, load available configuration, apply entry defaults, validate
      the interaction and links, insert owned rows, and attach only prepared file
      references.
    anchor: 'services-crm:modules/activities/services/persistence/activities.ts:saveNewActivity'
    seam: sync
    on_failure: Roll back record changes on invalid fields or unresolved references.
    left_inconsistent: Prepared file copies can remain outside the rolled-back record transaction.
    observer: The caller receives the validation or reference error.
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#writes
      nothing when the follow-up task is refused
  - 'n': 6
    actor_or_service: Follow-up task persistence
    action: >-
      Insert the requested follow-up with selected or defaulted type, related context,
      work day and due day inside the interaction transaction; synchronize enabled overdue
      attention.
    anchor: >-
      services-crm:modules/activities/services/persistence/activities.ts:createFollowUpTask
    seam: sync
    on_failure: A task or enabled attention refusal rolls back the interaction save.
    left_inconsistent: Prepared file copies are the remaining external preparation.
    observer: The caller receives the follow-up failure.
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#creates
      the follow-up task it is asked for, about the primary contact and the organization,
      due the type’s follow-up days after the activity
  - 'n': 7
    actor_or_service: Activity change settlement
    action: >-
      Capture the interaction and owned-row change under the caller’s attribution and
      settle its revision at commit; discard the event after settlement because no
      reaction is registered.
    anchor: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
    seam: sync
    on_failure: A capture or settlement failure prevents the transaction from committing.
    left_inconsistent: No partial record save survives that transaction failure.
    observer: Version History presents committed revisions.
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - 'n': 8
    actor_or_service: Linked-record timeline refresh
    action: >-
      Notify linked-record timelines to refresh and retain the chosen category for later
      entry.
    anchor: 'react-console:lib/activities/api.ts:createActivitiesApi'
    seam: sync
    on_failure: A failed refresh requires a later reload to recover the display.
    left_inconsistent: The saved record can be newer than the visible timeline.
    observer: The user observes the refreshed or older display.
    provenance: observed
    source: 'react-console:lib/activities/api.ts:createActivitiesApi'
branches:
  - 'Without a follow-up request, no task insertion is performed.'
  - >-
    History imports preserve supplied original attribution and match the imported source
    rather than a console digest.
  - >-
    A browser-calculated follow-up day can differ from the service default based on the
    interaction’s workspace day.
waits: []
evidence:
  - >-
    services-crm at a8d1364f: modules/activities/aws/api/activities.routes.ts
    (createActivity); services/persistence/activities.ts (createActivity,
    replayActivityCreate, saveNewActivity, createFollowUpTask); lib/db/create-replays.ts;
    modules/tasks/services/persistence/tasks.ts (createTaskWithOutcome);
    aws/crm.change-events.ts; docs/change-events.md; docs/record-history.md.
  - >-
    react-console at baf6dae3: components/activities/log-activity-sheet.tsx;
    lib/activities/api.ts (createActivity, retrySafeCreate).
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-IAM-001, TC-IAM-005, TC-IAM-006, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003]
---

# Log an activity with its links, files and follow-up

## What It Does

Interaction logging commits the interaction, its owned links and file entries, and any requested follow-up together. File preparation precedes that transaction, so record atomicity does not include the prepared copies. Creation recovery uses the same retained identifier while the created row exists.

## The Flow

```mermaid
flowchart TD
  A[Submit interaction draft] --> B{Live creation already exists?}
  B -->|Matching digest| C[Return existing interaction]
  B -->|Different digest| D[Reject conflicting creation]
  B -->|New creation| E[Prepare added file copies]
  E --> F[Begin record transaction and validate]
  F --> G[Insert interaction and owned context]
  G --> H{Follow-up requested?}
  H -->|Yes| I[Insert work and synchronize enabled attention]
  H -->|No| J[Settle interaction revision and commit]
  I --> J
  J --> K[Refresh linked-record displays]
```

The numbered hops specify the request, persistence and integration boundaries in order. Each hop identifies its evidence anchor, synchronization seam and observable failure outcome. Branches distinguish optional and delegated paths.

## When Something Fails

Validation, missing references and follow-up failures refuse the entire record save. Enabled attention also participates in a follow-up’s transaction and can prevent logging. An ambiguous network response requires recovery because a committed result may already exist; shared asset cleanup behavior beyond the local submission remains unverified.

## Open Design Questions

Product must settle the calendar anchor for suggested follow-ups and the meaning of an explicit No Owner selection during creation.
