# Data Model: Findings Notification Presentation Convergence ## Overview This feature introduces no new persisted business entity. Existing finding truth, operation-run truth, deep-link helpers, and database-notification rows remain canonical. The new work is a bounded derived presentation layer over those existing records. ## Existing Persistent Entities ### Database Notification (`notifications` table) **Purpose**: Existing persisted delivery artifact for operator-facing in-app notifications. **Key fields used by this feature**: - `id` - `type` - `notifiable_type` - `notifiable_id` - `data` - `read_at` - `created_at` **Rules relevant to convergence**: - The feature changes only the derived primary payload shape stored in `data`. - Existing namespaced metadata such as `finding_event`, `reason_translation`, and `diagnostic_reason_code` remains secondary and consumer-specific. - No new table or projection is added. ### Finding **Purpose**: Canonical tenant-scoped truth for finding identity, severity, lifecycle, and notification-event context. **Key fields used by this feature**: - `id` - `tenant_id` - `workspace_id` - `severity` - `status` - `owner_user_id` - `assignee_user_id` - `due_at` **Rules relevant to convergence**: - The feature does not change how finding events are generated. - Finding links continue to resolve against the existing tenant-panel detail route. - Finding-event metadata remains available for downstream consumers and tests. ### OperationRun **Purpose**: Canonical truth for operation lifecycle, scope, outcome, and supporting notification context. **Key fields used by this feature**: - `id` - `type` - `status` - `outcome` - `tenant_id` - `context` - `summary_counts` - `failure_summary` **Rules relevant to convergence**: - The feature does not change queued or terminal notification emit rules. - Existing admin-plane, tenantless, and system-plane link resolution remains authoritative. - Completed-run guidance and reason translation remain derived from current run truth. ### Notifiable Context **Purpose**: Determines which route family and supporting context a notification may expose. **Relevant notifiable cases**: - tenant-scoped operator receiving a finding notification - workspace operator receiving an admin-plane operation notification - platform user receiving a system-plane operation notification **Rules relevant to convergence**: - Shared presentation must not erase plane-specific destination behavior. - The shared contract can adapt the action URL by notifiable context, but it cannot widen visibility or flatten authorization semantics. ## Derived Models ### OperatorDatabaseNotificationPresentation **Purpose**: Shared derived contract for the primary structure rendered in the existing Filament notification drawer. **Fields**: - `title` - `body` - `status` - `primaryAction.label` - `primaryAction.url` - `primaryAction.target` - `supportingLines[]` - `metadata` **Validation rules**: - Every in-scope consumer provides exactly one primary action. - `status` remains the single source for the existing Filament icon treatment; the feature does not introduce a second icon taxonomy. - `supportingLines` is optional and never replaces `body` or the primary action. - `metadata` may carry consumer-specific namespaced fields, but the shared primary structure remains stable. ### NotificationPrimaryAction **Purpose**: Canonical one-action model for secondary context notifications. **Fields**: - `label` - `url` - `target` **Allowed targets**: - `finding_detail` - `admin_operation_run` - `tenantless_operation_run` - `system_operation_run` **Rules**: - There is exactly one primary action per in-scope card. - The action source remains the existing canonical link helper for that domain and plane. ### FindingNotificationPresentationInput **Purpose**: Consumer-specific derived input used by the shared contract for `FindingEventNotification`. **Fields**: - `findingId` - `tenantId` - `eventType` - `title` - `body` - `recipientReason` - `tenantName` - `severity` - `fingerprintKey` - `dueCycleKey` **Rules**: - Primary wording remains finding-first and uses `Open finding` as the action label. - `recipientReason` stays supporting context, not the headline. ### OperationRunNotificationPresentationInput **Purpose**: Consumer-specific derived input used by the shared contract for queued and terminal run notifications. **Fields**: - `runId` - `operationType` - `status` - `outcome` - `targetPlane` - `openUrl` - `openLabel` - `guidanceLines[]` - `summaryLine` - `reasonTranslation` **Rules**: - Queued notifications keep their existing queued vocabulary but adopt the shared card structure. - Completed notifications preserve terminal explanation, summary, and diagnostic fields as supporting context. - Platform users resolve to the system-panel run detail route; non-platform users keep current admin or tenantless behavior. ## Consumer Matrix | Consumer | Source truth | Primary action target | Required shared fields | Preserved secondary metadata | |----------|--------------|-----------------------|------------------------|------------------------------| | `FindingEventNotification` | `Finding` plus existing event envelope | tenant finding detail | title, body, status with existing icon treatment, `Open finding`, tenant-safe URL | `finding_event` with recipient reason, fingerprint, tenant name, severity | | `OperationRunQueued` | `OperationRun` queued state | admin or tenantless operation run view | title, body, status with existing icon treatment, open-run label, resolved URL | minimal context derived from current run state only | | `OperationRunCompleted` | `OperationRun` terminal state | admin, tenantless, or system operation run view | title, body, status with existing icon treatment, open-run label, resolved URL | `reason_translation`, `diagnostic_reason_code`, summary lines, failure guidance | ## Persistence Boundaries - No new table, enum-backed persistence, or presentation-only cache is introduced. - The shared notification contract remains derived from existing finding and operation-run truth. - Existing `notifications.data` remains the only persisted artifact for in-app delivery. - Existing event semantics from Spec 224 and current operation notification behavior remain unchanged.