TenantAtlas/specs/224-findings-notifications-escalation/data-model.md
2026-04-22 02:51:50 +02:00

7.8 KiB

Data Model: Findings Notifications & Escalation v1

Overview

This feature introduces no new persisted business entity. Existing finding truth, alert rules, alert deliveries, database notifications, and tenant-membership or capability truth remain canonical. The new work is a bounded derived-event layer over those existing records.

Existing Persistent Entities

Finding

Purpose: Canonical tenant-scoped finding truth for ownership, lifecycle, severity, and due-date evaluation.

Key fields used by this feature:

  • id
  • workspace_id
  • tenant_id
  • severity
  • status
  • due_at
  • sla_days
  • owner_user_id
  • assignee_user_id
  • reopened_at
  • resolved_at
  • closed_at
  • finding_type
  • subject_type
  • subject_external_id

Relationships:

  • belongs to one tenant
  • belongs to one workspace through tenant ownership
  • may reference one current owner user
  • may reference one current assignee user

Rules relevant to notifications:

  • Only open findings participate in assignment, due-soon, and overdue notification evaluation.
  • Terminal findings suppress due-soon and overdue delivery even if they previously entered a reminder window.
  • The current due cycle is keyed by due_at; reopened_at remains explanatory lifecycle context and only matters when the existing lifecycle recalculates due_at. No extra reminder-state field is added.
  • Existing aggregate sla_due alerts remain separate and are not replaced by finding-level delivery.

AlertRule

Purpose: Workspace-scoped configuration for optional external delivery copies.

Key fields used by this feature:

  • workspace_id
  • event_type
  • min_severity
  • destination_ids
  • cooldown_minutes
  • quiet_hours
  • enabled

Rules relevant to notifications:

  • The feature adds four new event_type values only.
  • A direct personal notification does not depend on an alert rule.
  • External copies still require an enabled matching rule and destination.

AlertDelivery

Purpose: Existing persisted artifact for external-copy dispatch outcomes.

Key fields used by this feature:

  • workspace_id
  • tenant_id
  • event_type
  • status
  • destination_snapshot
  • payload
  • fingerprint
  • suppressed_reason

Rules relevant to notifications:

  • Finding-level external copies reuse the same delivery pipeline, cooldown, suppression, and quiet-hours semantics as other alerts.
  • Delivery-history viewing remains read-only and only gains the new event labels and safe summaries.

Database Notification (notifications table)

Purpose: Existing persisted artifact for direct in-app notification delivery.

Key fields used by this feature:

  • id
  • type
  • notifiable_type
  • notifiable_id
  • data
  • read_at
  • created_at

Rules relevant to notifications:

  • The feature stores direct-delivery metadata and the deterministic fingerprint_key inside data; no new table is introduced.
  • The persisted payload remains Filament-compatible so the existing notification drawer can render it unchanged.

Tenant Membership and User Entitlement Context

Purpose: Current authorization truth for whether a resolved direct recipient may still inspect the tenant and finding at send time.

Key inputs used by this feature:

  • tenant_memberships.tenant_id
  • tenant_memberships.user_id
  • User::canAccessTenant($tenant)
  • CapabilityResolver::can($user, $tenant, Capabilities::TENANT_FINDINGS_VIEW) or the existing findings-view equivalent used by the implementation seam

Rules relevant to notifications:

  • Direct delivery is suppressed when the resolved recipient is no longer entitled.
  • Open-time route authorization remains authoritative even after send-time validation.

Derived Models

FindingNotificationEvent

Purpose: Canonical derived event envelope used by both direct personal delivery and optional external alert copies.

Fields:

  • event_type: one of findings.assigned, findings.reopened, findings.due_soon, findings.overdue
  • workspace_id
  • tenant_id
  • finding_id
  • severity
  • title
  • body
  • recipient_reason: one of new_assignee, current_assignee, current_owner
  • resolved_recipient_user_id: nullable
  • fingerprint_key
  • due_cycle_key: nullable, derived from current due_at
  • metadata: object with finding summary, owner and assignee ids, due date, reopen timestamp, and deep-link-safe context

Validation rules:

  • Event type must be one of the four new finding events.
  • recipient_reason must match the event-specific precedence rule.
  • fingerprint_key must deterministically distinguish the specific assignment change, reopen occurrence, or due cycle.
  • due_cycle_key is required for findings.due_soon and findings.overdue, and omitted or null for assignment and reopen.

RecipientResolutionResult

Purpose: Bounded contract that picks at most one direct recipient from existing owner and assignee truth without creating a second ownership model.

Fields:

  • user_id: nullable
  • reason: one of new_assignee, current_assignee, current_owner
  • is_entitled: boolean
  • suppression_reason: nullable string

Rules:

  • findings.assigned resolves to the new assignee only.
  • findings.reopened resolves to current assignee, else current owner.
  • findings.due_soon resolves to current assignee, else current owner.
  • findings.overdue resolves to current owner, else current assignee.
  • A recipient who is not currently entitled becomes a suppression result, not a broadened-delivery fallback.

DirectFindingNotificationMessage

Purpose: Filament database-notification payload rendered in the existing notification drawer.

Fields:

  • format = filament
  • title
  • body
  • actions[0].label = Open finding
  • actions[0].url = /admin/t/{tenant}/findings/{finding}
  • finding_event.event_type
  • finding_event.recipient_reason
  • finding_event.fingerprint_key
  • finding_event.tenant_name
  • finding_event.severity

Rules:

  • One notification row represents one direct delivery to one entitled user.
  • The payload must explain why the operator received the notification.
  • The payload must not include hidden-tenant data beyond what the recipient is entitled to inspect.

Event Matrix

Event type Trigger Recipient precedence Fingerprint components Suppression rules
findings.assigned An open finding is assigned to a new assignee new assignee finding id + target assignee id + assignment change marker suppress for owner-only changes, assignee clears, no-op saves, terminal findings, or non-entitled recipient
findings.reopened A terminal finding is reopened by system detection current assignee, else current owner finding id + reopened occurrence marker suppress for manual reopen, missing recipient, or non-entitled recipient
findings.due_soon An open finding first enters the 24-hour pre-due window for the current due cycle current assignee, else current owner finding id + current due_at + event type suppress for terminal findings, missing due_at, no entitled recipient, or duplicate within the same due cycle
findings.overdue An open finding first becomes overdue for the current due cycle current owner, else current assignee finding id + current due_at + event type suppress for terminal findings, no entitled recipient, or duplicate within the same due cycle

Persistence Boundaries

  • No new table, enum-backed persistence, or reminder-state model is introduced.
  • notifications.data stores direct-delivery fingerprint metadata only as a delivery artifact.
  • alert_deliveries stores external-copy artifacts only as it already does today.
  • Finding remains the sole business-truth model for ownership, lifecycle, and due-cycle resets.