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.activitieson a contact: type, description, due date, assignee, state.crm.activity_types, parametric and tenant-extensible, withis_systemseeds.- 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
messagingand theactivity.createdevent. - 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)
- An activity belongs to one contact, has one type, and is
pending,completedorcancelled. The state set is not tenant-extensible: it drives overdue logic and reporting. activity_typesis tenant-extensible. Tenant rows areis_system = false, scoped to that tenant, and a tenant can never modify or deactivate a system row.- 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.
- A due date is optional. An activity without one is a reminder without urgency, which is a real thing people write down.
- 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.
- Overdue is derived, never stored. A stored flag needs a job to maintain and will be wrong between runs.
- Deactivating a membership leaves that person’s activities assigned to them and surfaces them for reassignment, rather than silently reassigning or orphaning them.
- 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)
- A tenant-created activity type is visible only to that tenant.
- A tenant cannot modify or deactivate an
is_systemtype. - Assigning to a user outside the organization, or to a deactivated membership, is rejected.
- Overdue is derived at read time and is correct across timezones.
- A completed activity cannot be reopened; the API says so with a typed error.
- Deactivating a membership surfaces that person’s open activities for reassignment.
- Completion records who, when and the outcome.
- Negative: no endpoint adds a fourth activity state.