> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Vertical Event Taxonomies

> After this ships, a subscription business starts with invoice_paid, payment_late and service_anniversary already defined, instead of a blank page and a naming argument.

## Context

The hardest part of adopting an engagement platform is not the integration — it is deciding what to
send. A blank event schema means every tenant invents their own vocabulary, inconsistently, and
then their segments and rules inherit that inconsistency permanently.

DEC-H7 makes taxonomies **installable data, never code**. That is what lets the product apply to
any industry while still giving each one a running start, and it is what makes a new vertical a
content exercise rather than a release. The first is subscription services, because that is where
the design partner sits (DEC-I6).

The RFM templates that ship with a taxonomy matter as much as the event names: they turn "we now
collect events" into "here are your at-risk customers" on day one.

## Scope *(normative)*

* `core.event_taxonomies`: named, versioned, installable sets.
* `core.event_definitions`: event name, description, expected properties with types.
* Installation per tenant, additive, non-destructive.
* Validation of incoming event properties against the installed definition.
* Prebuilt RFM segment templates per taxonomy.
* The subscription-services taxonomy as the first shipped set.

## Non-scope *(normative)*

* **Rejecting events that are not in the taxonomy.** Validation warns; it never blocks ingestion. An
  integration that breaks because someone sent an undeclared event is worse than a loose schema.
* The onboarding wizard UI — `frontend/console`.
* Tenant-authored taxonomies published to other tenants. Not a marketplace.

## Behaviour *(normative)*

1. A taxonomy is **versioned and immutable once published**. Installing version 2 is an explicit
   act, never automatic, because it can change what validation expects.
2. Installation is **additive**: it adds definitions the tenant does not have and never overwrites
   one they customised.
3. A tenant may extend an installed taxonomy with their own definitions, and may start blank with
   no taxonomy at all.
4. Property validation against a definition **warns, never blocks** (§Non-scope). A mismatch is
   surfaced in the console and recorded, and the event is still ingested and still usable.
5. Removing a definition never removes the events already collected under it.
6. RFM templates install alongside their taxonomy as ordinary segment definitions the tenant can
   read and edit — they are a starting point, not a black box.
7. A taxonomy is data: adding a vertical means adding rows, and requires **no deploy**.
8. Event names follow the platform convention regardless of source: lowercase, snake\_case, past
   tense where it describes something that happened.

## Data *(normative)*

| Table                    | Key invariants                                                                                                                                                                  |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.event_taxonomies`  | `code` unique; `label`; `version`; `is_system`; immutable once published                                                                                                        |
| `core.event_definitions` | FK taxonomy nullable (null = tenant-authored); `tenant_id` nullable (null = system); `event_name`; `description`; `properties` JSONB schema; unique (`tenant_id`, `event_name`) |

## API *(normative)*

| Endpoint                                    | Class      | Permission                                      | Budget    |
| ------------------------------------------- | ---------- | ----------------------------------------------- | --------- |
| `GET /v1/core/taxonomies`                   | Management | `core.taxonomies.read`                          | p95 \<1 s |
| `POST /v1/core/taxonomies/{code}/install`   | Management | `core.taxonomies.install`                       | p95 \<5 s |
| `GET/POST/PATCH /v1/core/event-definitions` | Management | `core.event_definitions.{read\|create\|update}` | p95 \<1 s |

## Events *(normative)*

None. Installation is administrative and covered by the audit log.

## Acceptance criteria *(normative)*

1. Installing the subscription-services taxonomy creates its definitions and its RFM segment
   templates in one operation.
2. Re-installing is idempotent and does not overwrite a tenant-customised definition.
3. An event whose properties do not match its definition is **still ingested**, and the mismatch is
   recorded and visible.
4. A tenant can operate with no taxonomy installed and define events entirely on their own.
5. Removing a definition leaves historic events queryable.
6. Adding a new vertical taxonomy requires only new rows — proven by adding one in a test with no
   code change.
7. **Negative:** installation never deletes or overwrites an existing tenant definition.

## Execution

Single slice, synchronous command. F1b. Taxonomy content lives in seeds; installation is a
transactional copy into the tenant's definitions.

## Open questions

| # | Question                                                                         | Decides | By              |
| - | -------------------------------------------------------------------------------- | ------- | --------------- |
| 1 | Which vertical ships second — retail, or health/services? (PRD open question 1)  | Daniel  | before approval |
| 2 | Can a tenant install two taxonomies at once, and how do name collisions resolve? | Daniel  | before approval |

## Changelog

| Version | Date       | Change        | Why | Author                 |
| ------- | ---------- | ------------- | --- | ---------------------- |
| 0.1.0   | 2026-08-17 | Initial draft | —   | daniel + claude-opus-5 |

## Delivery record

*Not implemented yet.*
