---
id: DOM-CRM-ACT-001
title: Activity
realises: CON-CRM-ACT-001
product_area: crm
module: activities-tasks
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-CRM-ACT-activities
readable_by:
  - SVC-CRM-ENT-entities
lifecycle: STATE-CRM-ACT-001
custom_fields: none
identity: >-
  Each workspace identifies an interaction by one activity identifier. Console creation
  chooses a time-ordered identifier before sending and compares the stored request digest
  on replay; a conflicting request is rejected while the row exists. Imported source
  references are unique locally. Type identifiers are immutable configuration names, and
  an outcome identifier is unique within its type.
attributes:
  - name: activity type
    kind: reference
    required: true
    computed: false
    notes: >-
      The interaction category. Creation and a change of category require an active local
      type; retaining a category that was subsequently retired is permitted.
  - name: subject
    kind: text
    required: false
    computed: false
    notes: >-
      A short heading, limited to 500 characters. The type decides whether it is absent,
      optional or mandatory.
  - name: notes
    kind: text
    required: false
    computed: false
    notes: >-
      Formatted discussion content passes through HTML cleaning before storage. The
      cleaned value may contain at most 100,000 characters; a value reduced to empty is
      stored without content.
  - name: occurred at
    kind: date
    required: true
    computed: false
    notes: >-
      The interaction instant and whether a time was supplied. Creation defaults the
      instant to now; internal replacement retains an omitted instant.
  - name: end time and duration
    kind: number
    required: false
    computed: false
    notes: >-
      The optional end must be at or after the start. Duration ranges from zero to 1,440
      minutes, with a type default on creation unless duration is hidden.
  - name: status
    kind: enum
    required: true
    computed: false
    notes: >-
      The interaction is Completed, Scheduled or Cancelled. The type supplies the initial
      default; Scheduled places it in upcoming work.
  - name: direction
    kind: enum
    required: false
    computed: false
    notes: >-
      Inbound or outbound identifies who initiated the exchange. The baseline Call and
      Email categories require this detail.
  - name: outcome
    kind: reference
    required: false
    computed: false
    notes: >-
      The selected result belongs to the current category. New selections must be active;
      retaining a result that has been retired is allowed.
  - name: owner
    kind: reference
    required: false
    computed: false
    notes: >-
      The optional responsible user differs from creation and modification attribution. On
      ordinary user creation an omitted or empty owner becomes the caller; edits can clear
      it.
  - name: linked records
    kind: collection
    required: false
    computed: false
    notes: >-
      Ordinary saves accept one to 200 distinct local contact or organization links and
      select or default one primary. Record deletion can remove all links or the primary
      alone. Stored link copies of time, status and type support timeline reads.
  - name: attendees
    kind: computed
    required: false
    computed: true
    notes: >-
      Additional linked contacts beyond the primary provide the attendee set. A category
      may require at least one such contact.
  - name: attachments
    kind: collection
    required: false
    computed: false
    notes: >-
      The ordered supporting-file list holds at most 20 entries with names of at most 255
      characters. Every added file must be prepared for the activity by the shared
      pipeline.
  - name: origin and external reference
    kind: enum
    required: true
    computed: false
    notes: >-
      The service sets whether the interaction was entered manually, migrated, integrated
      or system-created. Edits retain that classification, and an optional external
      reference remains unique in the workspace.
  - name: record lock
    kind: enum
    required: false
    computed: false
    notes: >-
      The record can prohibit deletion alone or both updates and deletion. Ordinary writes
      can set the lock; a full lock has no supported clearing action.
  - name: version and stamps
    kind: computed
    required: true
    computed: true
    notes: >-
      Edits compare the read version before incrementing it. Creation and modification
      capture actor and time; reads resolve the current user names.
  - name: type · field modes
    kind: collection
    required: true
    computed: false
    notes: >-
      The type controls subject, direction, duration, outcome, end and attendees as
      hidden, optional or required. Required duration and outcome apply on completion;
      hidden attendees do not forbid extra links.
  - name: 'type · starting status, default duration and follow-up suggestion'
    kind: number
    required: false
    computed: false
    notes: >-
      The starting status is Completed or Scheduled. Suggested duration ranges from one to
      1,440 minutes and suggested follow-up from one to 365 days.
  - name: type · outcomes
    kind: collection
    required: false
    computed: false
    notes: >-
      Each type maintains up to 50 ordered, uniquely named results with individual
      availability. A supplied result list replaces the previous list; an omitted list
      preserves it.
  - name: 'type · built-in code, appearance, order and active switch'
    kind: enum
    required: true
    computed: false
    notes: >-
      Baseline categories have a fixed built-in code. Types also carry constrained icon
      and colour choices, display position and availability for new selections.
relationships:
  - to: DOM-CRM-ENT-001
    cardinality: many-to-many through owned links; ordinary saves require one to 200 links overall
    ownership: >-
      Activity owns the association. Removing a contact cascades only its links and
      preserves the interaction.
    cross_service: false
  - to: DOM-CRM-ENT-002
    cardinality: many-to-many through owned links
    ownership: >-
      Activity also owns organization associations; removing an organization drops its
      links without deleting the interaction.
    cross_service: false
  - to: DOM-CRM-ACT-003
    cardinality: zero or one follow-up task requested by an activity create
    ownership: >-
      Task creation shares the save transaction, then the work continues independently
      without an activity pointer.
    cross_service: false
  - to: DOM-CRM-ACT-005
    cardinality: one appearance per retained link on the corresponding record timeline
    ownership: The timeline consumes linked activity data and persists no copy.
    cross_service: false
invariants:
  - id: INV-DOM-CRM-ACT-001-01
    statement: >-
      An ordinary create or edit supplies one to 200 distinct local contact or
      organization links, each identifying exactly one record; record deletion may later
      leave no links.
    enforced_at:
      - api
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      an activity linked to nothing;
      services-crm:modules/activities/db/activity-links.table.ts:activityLinks
  - id: INV-DOM-CRM-ACT-001-02
    statement: >-
      Ordinary saves choose or default one primary link, while the database forbids
      multiple primaries and permits no primary after deletion of the selected record.
    enforced_at:
      - service
      - database
    provenance: observed
    source: >-
      services-crm:modules/activities/services/persistence/activities.ts:linksAsWritten;
      modules/activities/db/activity-links.table.ts:activity_links_one_primary_uidx
  - id: INV-DOM-CRM-ACT-001-03
    statement: >-
      The database keeps the outcome within the selected activity type, and the service
      requires active types and outcomes for new selections.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      an outcome of another type
  - id: INV-DOM-CRM-ACT-001-04
    statement: >-
      Saves apply the type’s field modes and collect field-mode problems together,
      requiring duration and outcome only for Completed interactions.
    enforced_at:
      - service
      - console
    provenance: observed
    source: 'services-crm:modules/activities/services/activities/field-modes.ts:fieldModeProblems'
  - id: INV-DOM-CRM-ACT-001-05
    statement: >-
      Stored end time cannot precede start time, duration stays within zero to 1,440
      minutes, subject within 500 characters and cleaned notes within 100,000 characters.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      an end before the start
  - id: INV-DOM-CRM-ACT-001-06
    statement: >-
      While the created row exists, replaying the same identifier and request digest
      returns it without another follow-up or file preparation; a different digest
      conflicts.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#makes
      one activity
  - id: INV-DOM-CRM-ACT-001-07
    statement: >-
      Ordinary edits reject a stale read version before committing a change; deletion
      takes no read version.
    enforced_at:
      - api
      - service
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a replace
      of a version it has moved on from: 409
  - id: INV-DOM-CRM-ACT-001-08
    statement: >-
      A saved attachment reference must already belong to the activity or come from
      preparation performed for the current save.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      a file reference that did not come through the pipeline
  - id: INV-DOM-CRM-ACT-001-09
    statement: >-
      Ordinary edits preserve the service-selected origin, and external activity
      references cannot repeat within a workspace.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#records
      sys_origin and sys_external_id from the source it is given
  - id: INV-DOM-CRM-ACT-001-10
    statement: >-
      A committed activity transaction captures its activity, link and attachment changes
      in one attributed revision that remains after activity deletion.
    enforced_at:
      - database
    provenance: documented
    source: 'services-crm:docs/record-history.md#What a revision is'
  - id: INV-DOM-CRM-ACT-001-11
    statement: >-
      The service rejects edits under a full lock and rejects deletion under either
      supported lock.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      a locked activity
  - id: INV-DOM-CRM-ACT-001-12
    statement: >-
      Referenced types and outcomes cannot be removed, and a baseline type cannot be
      deleted even when unused; refusal directs administrators to retirement.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activity-types.integration.spec.js#refuses
      a system type, saying to deactivate it instead
  - id: INV-DOM-CRM-ACT-001-13
    statement: >-
      Built-in type codes remain service-controlled and locally unique, with direction
      mandatory for baseline Call and Email.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/db/activities.table.integration.spec.js#refuses
      a second type of the tenant with the same system code
  - id: INV-DOM-CRM-ACT-001-14
    statement: >-
      The API rejects custom-field values for activities and their supporting
      configuration because these objects do not declare that capability.
    enforced_at:
      - api
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a custom
      field value, an activity having no custom fields (R2-ARCH-001): 400 naming
      custom_fields
  - id: INV-DOM-CRM-ACT-001-15
    statement: >-
      Type names are locally unique and at most 100 characters, outcome names are unique
      within a type, and complete-list reordering commits all positions together.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activity-types.integration.spec.js#refuses
      a name another type of the tenant has
physical:
  - activities
  - activity_links
  - activity_attachments
  - activity_types
  - activity_outcomes
  - activity_change_events
  - record_revisions
evidence:
  - >-
    services-crm at a8d1364f: modules/activities/db/*.table.ts;
    modules/entities/db/contacts-for-queries.view.ts and organizations-for-queries.view.ts
    (activity summaries); services/persistence/activities.ts (createActivity,
    updateActivity, deleteActivity, activityValuesOf, requireActivityRules,
    linksAsWritten, replaceActivityLinks, requireActivityAttachmentAssets);
    services/persistence/activity-types.ts (header); services/activities/field-modes.ts,
    activity-body.ts; metadata/activities.object.ts; history/activity-history.config.ts;
    aws/crm.change-events.ts (activity stream); docs/record-history.md;
    docs/migrations/activities/README.md (§2 to §9).
  - >-
    react-console at baf6dae3: components/activities/log-activity-sheet.tsx;
    lib/activities/api.ts.
---

# Activity

## What It Models

Staff use an activity to retain the context of an interaction. A shared conversation has one record and associations to its participating people and organizations. Classification, outcomes and supporting files are facets of that interaction, with the type supplying the entry settings.

## Identity and Attributes

The identifier distinguishes an interaction from its changing subject and participants. A console request retains its creation identifier for recovery, while an import can retain its external reference for matching. Logical attributes cover the interaction, its supporting context, ownership and write safeguards; the structured rows specify their limits and defaults.

## Relationships

Activity owns the links to CRM records. Follow-up creation calls Task inside the logging transaction, after which the work has an independent lifecycle. Record Timeline presents an interaction through each surviving association.

## Invariants

The structured invariants distinguish ordinary save requirements from retention after record deletion. In particular, a deletion cascade does not reselect a primary or enforce a minimum number of surviving links. Existing planning findings retain the discrepancies involving ownership defaults, locks and console limits.

## How It Is Stored and Shared

The activities service owns persistence and exposes the link-transfer function used during a merge. Database cascades provide the deletion exception to normal writes. Entities query views read links for summaries, Platform queries consume registered datasets, and the activity creation path delegates follow-up persistence to Task. History uses shared revision infrastructure with an activity-specific presentation configuration.

## Open Design Questions

Authorized management of retained interactions without links still needs its recorded product behavior implemented. Product also needs to settle consistent entry limits and the calendar used for suggested follow-ups.
