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 ID | Title | Priority |
|---|---|---|
| REQ-NOTIF-001 | Display Runfile Status Notifications | Must |
| REQ-NOTIF-002 | Filter Runfile by Notification Selection | Must |
| REQ-NOTIF-003 | Display Associate Control Error Notifications | Must |
| REQ-NOTIF-004 | Configure Comment Counting Behavior | Must |
| REQ-NOTIF-005 | Display Mix-Specific Label Error Counts | Must |
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
| Direction | Domain/Component | Purpose |
|---|---|---|
| Consumes | Well Model | Well status data |
| ErrorCode Model | Error type classification | |
| Comment Model | Comment counts, system-generated flag | |
| ClientConfiguration | Comment counting setting | |
| Provides to | RUNFILE | Notification display in run list |
| RUNRPT | Notification display on run page |
2. Component Architecture
2.1 Component Diagram
2.2 Component Responsibilities
| Component | Layer | Responsibility | REQ Trace |
|---|---|---|---|
Well | Backend Model | Stores well status, error type, mix assignment | REQ-NOTIF-001, 003, 005 |
ErrorCode | Backend Model | Defines error types (Label Error, Associate Control Error) | REQ-NOTIF-003, 005 |
Comment | Backend Model | Stores comments with is_system_generated flag | REQ-NOTIF-004 |
ClientConfiguration | Backend Model | Stores count_system_generated_comments setting | REQ-NOTIF-004 |
GetRunStatus | Backend Service | Aggregates well counts by status category | REQ-NOTIF-001, 002 |
NotificationContext | Frontend | State management for notification data | REQ-NOTIF-001 |
NotificationGroup | Frontend | Container for notification badges | REQ-NOTIF-001 |
NotificationBadge | Frontend | Individual status badge with count and tooltip | REQ-NOTIF-001, 003 |
NotificationFilter | Frontend | Click handler for filtering wells | REQ-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.
| Entity | Owner | Usage in NOTIF |
|---|---|---|
wells | RUNRPT | Read status, error_type, mix_id |
error_codes | ERRORCODES | Read error type definitions |
comments | COMMENTS | Read comment counts, is_system_generated |
client_configurations | CLIENTCFG | Read 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
| Endpoint | Method | Purpose | Response Fields Used |
|---|---|---|---|
/api/runs | GET | Run list with notifications | notifications: NotificationCounts |
/api/runs/:id | GET | Single run with notifications | notifications: 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
| Event | Direction | Payload | Purpose |
|---|---|---|---|
filter:apply | Frontend internal | { category: NotificationCategory } | User clicked a badge |
filter:clear | Frontend internal | {} | User cleared filter |
run:updated | Pusher → 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
| Condition | Detection | Response | User Impact |
|---|---|---|---|
| API timeout | Network error | Retry with exponential backoff | Stale counts shown |
| Invalid run_id | 404 response | Log error, show empty counts | No notifications shown |
| Pusher disconnect | Connection lost | Reconnect, refetch counts | Counts may be stale |
7. Configuration
| Setting | Location | Default | Effect |
|---|---|---|---|
count_system_generated_comments | client_configurations | true | Include/exclude system comments in count |
See Configuration Reference for details.
8. Implementation Mapping
8.1 Code Locations
| Component | Type | Path |
|---|---|---|
| Well | Model | code/app/Well.php |
| ErrorCode | Model | code/app/ErrorCode.php |
| Comment | Model | code/app/Comment.php |
| ClientConfiguration | Model | code/app/ClientConfiguration.php |
| GetRunStatus | Service | code/app/GetRunStatus.php |
| NotificationBadge | Component | code/components/app-notifications/NotificationBadge.vue |
| NotificationGroup | Component | code/components/app-notifications/NotificationGroup.vue |
8.2 Requirement Traceability
| REQ ID | Design Section | Code Location |
|---|---|---|
| REQ-NOTIF-001 | §5.1 Aggregation | GetRunStatus.php, NotificationBadge.vue |
| REQ-NOTIF-002 | §5.2 Filter Application | NotificationFilter.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-Level | GetRunStatus.php, MixNotifications.vue |
9. Design Decisions
| Decision | Rationale | Alternatives Considered |
|---|---|---|
| Frontend aggregation display, backend data | Separation of concerns; backend provides raw data, frontend handles presentation | Backend pre-computed counts (rejected: less flexible) |
| Associate Control Error as separate category | Business requirement to distinguish from general errors | Single error category (rejected: loses visibility) |
| Pusher for real-time updates | Existing infrastructure, low latency | Polling (rejected: higher load), SSE (rejected: less browser support) |
| Config-driven comment counting | Different labs have different policies | Hardcoded behavior (rejected: inflexible) |
10. Related Documents
| Document | Relevant Sections |
|---|---|
| SRS: notif.md | Requirements source |
| SDS: Architecture | Pusher integration |
| SDS: RUNRPT Domain | Parent display context |