Skip to main content

Context

An activity is the smallest useful unit of follow-up: something to do, about a customer, by a date, by someone. crm.activity_types is one of only two tenant-extensible catalogs in the platform (DEC-B4), and the reason is exactly the rule the data standard states: the values are the tenant’s own business vocabulary. A gym logs “class no-show”, a clinic logs “appointment reminder”, a distributor logs “quarterly visit”. Those are not ours to enumerate. What stays ours is the state machine — an activity is pending, completed or cancelled, and a tenant cannot add a fourth state, because the state drives logic.

Scope (normative)

  • crm.activities on a contact: type, description, due date, assignee, state.
  • crm.activity_types, parametric and tenant-extensible, with is_system seeds.
  • Assignment to a user in the same organization.
  • Completion with an outcome note.
  • Overdue detection and listing.

Non-scope (normative)

  • Reminders and notifications — F1b, through messaging and the activity.created event.
  • Recurring activities. A recurrence engine is a scheduler, and we have one for campaigns; reusing it here needs its own design.
  • SLAs, queues and escalation. That is ticketing, and it is a non-goal of the module.
  • Calendar sync — not planned.

Behaviour (normative)

  1. An activity belongs to one contact, has one type, and is pending, completed or cancelled. The state set is not tenant-extensible: it drives overdue logic and reporting.
  2. activity_types is tenant-extensible. Tenant rows are is_system = false, scoped to that tenant, and a tenant can never modify or deactivate a system row.
  3. The assignee must be an active member of the same organization. Assigning to someone who has left is rejected, which is also a small nudge to keep memberships current.
  4. A due date is optional. An activity without one is a reminder without urgency, which is a real thing people write down.
  5. Completion records who and when, plus an optional outcome. Reopening a completed activity is not allowed — the correct action is a new one, so the history stays honest.
  6. Overdue is derived, never stored. A stored flag needs a job to maintain and will be wrong between runs.
  7. Deactivating a membership leaves that person’s activities assigned to them and surfaces them for reassignment, rather than silently reassigning or orphaning them.
  8. Every mutation writes to core.audit_log.

Data (normative)

API (normative)

Events (normative)

crm.activity.created and crm.activity.completed. created is what F1b’s reminder feature will consume — the event exists now so adding reminders needs no change here.

Acceptance criteria (normative)

  1. A tenant-created activity type is visible only to that tenant.
  2. A tenant cannot modify or deactivate an is_system type.
  3. Assigning to a user outside the organization, or to a deactivated membership, is rejected.
  4. Overdue is derived at read time and is correct across timezones.
  5. A completed activity cannot be reopened; the API says so with a typed error.
  6. Deactivating a membership surfaces that person’s open activities for reassignment.
  7. Completion records who, when and the outcome.
  8. Negative: no endpoint adds a fourth activity state.

Execution

Single slice, synchronous command. Nothing asynchronous — reminders in F1b will consume the event.

Open questions

Changelog

Delivery record

Not implemented yet.