# Umbraco integration

In-process Umbraco plugins that ship every CMS lifecycle event (content / media / member / user) to ActivityLog over OTLP.

**Status: in development.** The v13 base plugin and KB extension are spec-complete; implementation is in flight. This page describes the shape; defer to the SPECs for the canonical contract.

## Two packages

| Package | Scope |
|---|---|
| `MC9.ActivityLog.Umbraco.V13` | Base v13 plugin — catches the 19 standard Umbraco notification types (`ContentSavedNotification`, `MediaDeletedNotification`, `MemberSavingNotification`, etc.) and emits one OTel `LogRecord` per event |
| `MC9.ActivityLog.Umbraco.KB` | KB-specific extension — decorates `IFyinLogService` and `ITicketHistoryService` so KB's existing audit writes also emit to ActivityLog (no call-site changes inside KB) |

For Umbraco v17 hosts (Momentus-CMS, ActivityLog-CMS itself) a separate `Umbraco.V17` package is planned.

## How it differs from native ingest

This is **Pattern 2** per `../../../ActivityLog-Integrations/Common-Architecture.md` § 2: an in-process plugin that emits via OpenTelemetry rather than a standalone Function App pulling from an external source.

Transport: OTLP exporter → `POST https://api.activitylog.com/api/v1/otlp/v1/logs`. The OTel SDK provides the batching, retry, and graceful shutdown — there's no custom dispatcher in this plugin.

## What you'll see

Each Umbraco event becomes one `Message` row with:

- `type` set to the notification name (e.g. `umbraco.content.saved`, `umbraco.media.deleted`, `umbraco.member.created`)
- `metadata.activitylog.actor.*` — the back-office user or member who triggered the event
- `metadata.activitylog.item.*` — the entity that changed (content/media/member/user)
- `metadata.activitylog.partner.*` — when the host implements a partner/project hierarchy (KB does this)
- `serviceName` — the configured service name (e.g. `"kb"`, `"momentus-cms"`)

The `activitylog.*` attributes are canonical across all integrations — see `../../../ActivityLog-Integrations/Common-Architecture.md` § 5.

## Setup (when the package is published)

1. **Mint a token.** Portal → Systems → **+ Mint new system** (name it ending in `kb`, for example `acme-kb`, so the Knowledge base report finds it) → copy the token shown once; mint further tokens with **+ Mint token** on the system page, 5-year retention. Note the token's `al_…` value.
2. **Install the NuGet package** in your Umbraco project:
   ```
   dotnet add package MC9.ActivityLog.Umbraco.V13
   ```
   (Plus `MC9.ActivityLog.Umbraco.KB` if you're running KB.)
3. **Configure** in `appsettings.json`:
   ```json
   {
     "ActivityLog": {
       "Endpoint":       "https://api.activitylog.com/api/v1/otlp/v1/logs",
       "Token":          "al_REPLACE_WITH_YOUR_TOKEN",
       "ServiceName":    "your-app-name"
     }
   }
   ```
4. **Register in startup**:
   ```csharp
   builder.Services.AddActivityLogUmbracoV13(builder.Configuration);
   builder.Services.AddActivityLogUmbracoKb(builder.Configuration); // KB hosts only
   ```
5. **Restart Umbraco.** First content save / member sign-in should appear in the portal Messages view within seconds.

## KB host — decorator strategy

KB already has a complete first-party audit trail (the `fyinEventLogs` and `fyinTicketHistory` tables, with ~80 audit-write call sites across KB's service layer). Rather than duplicate those events via the v13 notification handlers, the KB extension **wraps `IFyinLogService` and `ITicketHistoryService` with decorators** that also emit an OTel record on each audit write.

Result: no call-site changes inside KB. ~50 lines of decorator code captures every existing audit emit.

In the KB host config, the v13 base plugin's notification handlers are **disabled by default** (config-toggleable for verification). This avoids duplicate events.

See `../../../ActivityLog-Integrations/Umbraco/KB/SPEC.md` for the full strategy.

## Why OTel instead of native?

- Eats our own dogfood — ActivityLog's pitch is "point your OTel collector at us"; the platform's own plugins should too.
- The OTel SDK provides bounded queue, batched dispatch, retry/backoff, drop metrics — none of which we'd want to re-implement.
- Customers emitting their own OTel can ship to the same endpoint with the same `activitylog.*` attribute schema, no proprietary client.

## Status

| Component | Status |
|---|---|
| `MC9.ActivityLog.Umbraco.V13` | Spec complete; implementation pending |
| `MC9.ActivityLog.Umbraco.KB` | Spec complete; implementation pending |
| `MC9.ActivityLog.Umbraco.V17` | Planned (Momentus-CMS, ActivityLog-CMS itself) |
| NuGet package on Fyin feed | Not yet published |

When implementation lands the package will be on Fyin's internal NuGet feed (link in the README of the Umbraco directory in the Integrations repo).

### How KB activity arrives today

Until the plugin ships, Fyin's knowledge base (kb.fyin.com) reaches ActivityLog through an importer that reads KB's own audit tables on a timer and sends the activity with `POST /api/v1/messages/batch` to a system named `umbraco-kb`. The plugin will write to the same system with the same ids, so nothing changes for reports when it takes over. The [Knowledge base report](./90-reports.md#knowledge-base) reads your systems of kind `kb` (a system whose name ends in `kb`).

## What's next

| Goal | Doc |
|---|---|
| Full v13 base spec | `../../../ActivityLog-Integrations/Umbraco/v13/SPEC.md` |
| KB extension spec | `../../../ActivityLog-Integrations/Umbraco/KB/SPEC.md` |
| Common attribute schema | `../../../ActivityLog-Integrations/Common-Architecture.md` § 5 |
| OTLP transport details | [`51-ingest-otlp.md`](./51-ingest-otlp.md) |
