Skip to main content
Version: 3.0.1

Notification Indicators Design

Document Type: Domain Design (Tier 2) Domain: NOTIF Domain Character: Thin orchestration SRS Reference: notif.md Status: Draft Last Updated: 2026-01-25


1. Overview

1.1 Purpose

The Notification Indicators subsystem provides visual status summaries for runfiles, showing counts of wells in each status category. It enables users to quickly assess run health and filter wells by clicking notification badges.

This is primarily a frontend concern with backend data aggregation support. The backend provides well state data; the frontend aggregates, displays, and handles interaction.

1.2 Requirements Covered

REQ IDTitlePriority
REQ-NOTIF-001Display Runfile Status NotificationsMust
REQ-NOTIF-002Filter Runfile by Notification SelectionMust
REQ-NOTIF-003Display Associate Control Error NotificationsMust
REQ-NOTIF-004Configure Comment Counting BehaviorMust
REQ-NOTIF-005Display Mix-Specific Label Error CountsMust

1.3 Constraints

Tier 2 Constraint: This document describes ownership, patterns, and design rationale. It links to reference docs for full schemas and API specifications.

1.4 Dependencies

DirectionDomain/ComponentPurpose
ConsumesWell ModelWell status data
ErrorCode ModelError type classification
Comment ModelComment counts, system-generated flag
ClientConfigurationComment counting setting
Provides toRUNFILENotification display in run list
RUNRPTNotification display on run page

2. Component Architecture

2.1 Component Diagram

2.2 Component Responsibilities

ComponentLayerResponsibilityREQ Trace
WellBackend ModelStores well status, error type, mix assignmentREQ-NOTIF-001, 003, 005
ErrorCodeBackend ModelDefines error types (Label Error, Associate Control Error)REQ-NOTIF-003, 005
CommentBackend ModelStores comments with is_system_generated flagREQ-NOTIF-004
ClientConfigurationBackend ModelStores count_system_generated_comments settingREQ-NOTIF-004
GetRunStatusBackend ServiceAggregates well counts by status categoryREQ-NOTIF-001, 002
NotificationContextFrontendState management for notification dataREQ-NOTIF-001
NotificationGroupFrontendContainer for notification badgesREQ-NOTIF-001
NotificationBadgeFrontendIndividual status badge with count and tooltipREQ-NOTIF-001, 003
NotificationFilterFrontendClick handler for filtering wellsREQ-NOTIF-002

3. Data Design

3.1 Entities

This domain does not own persistent entities. It consumes read-only data from RUNRPT, ERRORCODES, COMMENTS, and CLIENTCFG.

EntityOwnerUsage in NOTIF
wellsRUNRPTRead status, error_type, mix_id
error_codesERRORCODESRead error type definitions
commentsCOMMENTSRead comment counts, is_system_generated
client_configurationsCLIENTCFGRead count_system_generated_comments

See Database Reference for full schema.

3.2 Data Structures

Notification Counts (API Response)

interface NotificationCounts {
unrecognised: number; // Wells not matching expected identifiers
errors: number; // Wells with error-level violations (excluding ACE)
warnings: number; // Wells with warning-level violations
exportable: number; // Wells eligible for export
comments: number; // Wells with comments (filtered by config)
associate_control_error: number; // ACE wells (separate from errors)
}

interface MixNotifications {
mix_id: string;
mix_name: string;
label_errors: number; // Label Error count for this mix
}

Filter State (Frontend)

interface NotificationFilterState {
active_filter: NotificationCategory | null;
counts: NotificationCounts;
mix_notifications: MixNotifications[];
}

type NotificationCategory =
| 'unrecognised'
| 'errors'
| 'warnings'
| 'exportable'
| 'comments'
| 'associate_control_error';

3.3 State Transitions

This domain is stateless. All operations are request-scoped.


4. Interface Design

4.1 APIs Consumed

EndpointMethodPurposeResponse Fields Used
/api/runsGETRun list with notificationsnotifications: NotificationCounts
/api/runs/:idGETSingle run with notificationsnotifications: NotificationCounts, mix_notifications: MixNotifications[]

4.2 APIs Provided

This domain does not provide APIs to other domains. It consumes aggregated data from the Run API.

4.3 Events

EventDirectionPayloadPurpose
filter:applyFrontend internal{ category: NotificationCategory }User clicked a badge
filter:clearFrontend internal{}User cleared filter
run:updatedPusher → Frontend{ run_id, notifications }Real-time count update

5. Behavioral Design

5.1 Notification Count Aggregation

Algorithm: Calculate Notification Counts

Inputs:
- run_id: UUID - The run to aggregate notifications for
- client_config: ClientConfiguration - Client-level settings

Outputs:
- counts: NotificationCounts - Aggregated counts per category

Assumptions:
- Wells have been fully analyzed (status, error_type populated)
- Comments have is_system_generated flag set correctly
- Deleted comments are soft-deleted (is_deleted flag)

Steps:
1. Load all wells for run_id
2. Initialize counts = { unrecognised: 0, errors: 0, warnings: 0,
exportable: 0, comments: 0, associate_control_error: 0 }
3. For each well:
a. If well.status == 'unrecognised': counts.unrecognised++
b. If well.has_error AND well.error_type != 'ASSOCIATE_CONTROL_ERROR':
counts.errors++
c. If well.error_type == 'ASSOCIATE_CONTROL_ERROR':
counts.associate_control_error++
d. If well.has_warning: counts.warnings++
e. If well.is_exportable: counts.exportable++
f. comment_count = count_comments(well, client_config)
If comment_count > 0: counts.comments++
4. Return counts

Notes:
- A well can appear in multiple counts (e.g., error AND has comments)
- Associate Control Error is mutually exclusive with general errors
- The comments count is wells-with-comments, not total comment count

Helper: count_comments

Algorithm: Count Comments for Well

Inputs:
- well: Well - The well to count comments for
- config: ClientConfiguration - Contains count_system_generated_comments flag

Outputs:
- count: integer - Number of comments matching criteria

Steps:
1. If config.count_system_generated_comments == true:
Return count of comments WHERE is_deleted = false
2. Else:
Return count of comments WHERE is_deleted = false
AND is_system_generated = false

5.2 Filter Application

5.3 Mix-Level Label Error Calculation

Algorithm: Calculate Mix-Level Label Errors

Inputs:
- run_id: UUID - The run to calculate mix notifications for

Outputs:
- mix_notifications: MixNotifications[] - Per-mix label error counts

Assumptions:
- Wells have mix_id foreign key populated
- Label errors are identified by error_type = 'LABEL_ERROR'

Steps:
1. Load all wells for run_id with mix relationships
2. Group wells by mix_id
3. For each mix:
a. Count wells where error_type == 'LABEL_ERROR'
b. Create MixNotifications { mix_id, mix_name, label_errors: count }
4. Return array of MixNotifications

Notes:
- Mixes with zero label errors are still included in output
- Only LABEL_ERROR type counts; other error types excluded

6. Error Handling

ConditionDetectionResponseUser Impact
API timeoutNetwork errorRetry with exponential backoffStale counts shown
Invalid run_id404 responseLog error, show empty countsNo notifications shown
Pusher disconnectConnection lostReconnect, refetch countsCounts may be stale

7. Configuration

SettingLocationDefaultEffect
count_system_generated_commentsclient_configurationstrueInclude/exclude system comments in count

See Configuration Reference for details.


8. Implementation Mapping

8.1 Code Locations

ComponentTypePath
WellModelcode/app/Well.php
ErrorCodeModelcode/app/ErrorCode.php
CommentModelcode/app/Comment.php
ClientConfigurationModelcode/app/ClientConfiguration.php
GetRunStatusServicecode/app/GetRunStatus.php
NotificationBadgeComponentcode/components/app-notifications/NotificationBadge.vue
NotificationGroupComponentcode/components/app-notifications/NotificationGroup.vue

8.2 Requirement Traceability

REQ IDDesign SectionCode Location
REQ-NOTIF-001§5.1 AggregationGetRunStatus.php, NotificationBadge.vue
REQ-NOTIF-002§5.2 Filter ApplicationNotificationFilter.vue, WellsTable.vue
REQ-NOTIF-003§5.1 (step 3c)Well.php (error_type), ErrorCode.php
REQ-NOTIF-004§5.1 (step 3f)Comment.php, ClientConfiguration.php
REQ-NOTIF-005§5.3 Mix-LevelGetRunStatus.php, MixNotifications.vue

9. Design Decisions

DecisionRationaleAlternatives Considered
Frontend aggregation display, backend dataSeparation of concerns; backend provides raw data, frontend handles presentationBackend pre-computed counts (rejected: less flexible)
Associate Control Error as separate categoryBusiness requirement to distinguish from general errorsSingle error category (rejected: loses visibility)
Pusher for real-time updatesExisting infrastructure, low latencyPolling (rejected: higher load), SSE (rejected: less browser support)
Config-driven comment countingDifferent labs have different policiesHardcoded behavior (rejected: inflexible)

DocumentRelevant Sections
SRS: notif.mdRequirements source
SDS: ArchitecturePusher integration
SDS: RUNRPT DomainParent display context