docs: add ETL pipeline viewer component design
Design document for admin monitoring component that visualizes: - Pipeline configuration from pipelines.json - Execution status (last run, next required, overdue) - Recent execution history (last 10 per schedule type) - Schedule sections for Mass/Daily/Hourly with defaults vs overrides
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
# ETL Pipeline Viewer Component Design
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Build a Blazor component that visualizes ETL pipeline configuration and execution status.
|
||||
|
||||
**Architecture:** Single-page admin component with pipeline selector, execution status tables, and vertical configuration sections for each schedule type (Mass, Daily, Hourly).
|
||||
|
||||
**Tech Stack:** Blazor WebAssembly, Radzen components, existing DataUpdate repository
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A read-only admin monitoring page that displays:
|
||||
1. Pipeline configuration details from `pipelines.json`
|
||||
2. Execution status (last run, next required, overdue status)
|
||||
3. Recent execution history (last 10 runs per schedule type)
|
||||
|
||||
## Component Structure
|
||||
|
||||
### Page Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ETL Pipeline Configuration Viewer │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Pipeline: [Dropdown - Alphabetical list] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ SCHEDULE STATUS SUMMARY (Table 1) │
|
||||
│ ┌─────────┬────────────────────┬─────────────────┬────────┐ │
|
||||
│ │ Type │ Last Successful │ Next Required │ Status │ │
|
||||
│ ├─────────┼────────────────────┼─────────────────┼────────┤ │
|
||||
│ │ Mass │ 2026-01-05 02:00 │ 2026-01-12 02:00│ ✓ OK │ │
|
||||
│ │ Daily │ 2026-01-07 01:00 │ 2026-01-08 01:00│ ✓ OK │ │
|
||||
│ │ Hourly │ 2026-01-07 10:00 │ 2026-01-07 11:00│ ⚠ Over │ │
|
||||
│ └─────────┴────────────────────┴─────────────────┴────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ RECENT EXECUTION HISTORY (Table 2 - Last 10 per type) │
|
||||
│ ┌─────────┬────────────┬──────────┬─────────┬─────┬───────┐ │
|
||||
│ │ Type │ Start │ End │ Duration│ Rows│ Result│ │
|
||||
│ ├─────────┼────────────┼──────────┼─────────┼─────┼───────┤ │
|
||||
│ │ Hourly │ 10:00 AM │ 10:02 AM │ 2m 15s │1,247│ ✓ │ │
|
||||
│ │ Hourly │ 09:00 AM │ 09:01 AM │ 1m 42s │ 892 │ ✓ │ │
|
||||
│ │ ... │ │ │ │ │ │ │
|
||||
│ └─────────┴────────────┴──────────┴─────────┴─────┴───────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ COMMON PIPELINE INFO │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Source: [JDE] Connection │ │
|
||||
│ │ Parameters: dateUpdated (jdeJulian), timeUpdated (jdeTime)│
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Destination: WorkOrder_Curr │ │
|
||||
│ │ Operation: Bulk Merge │ │
|
||||
│ │ Match: WorkOrderNumber, BranchCode │ │
|
||||
│ │ Exclude: WorkOrderNumber, BranchCode, LastUpdateDt │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Pre-Scripts: 0 scripts │ │
|
||||
│ │ Post-Scripts: 3 scripts [View] │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ MASS REFRESH [Enabled] │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Schedule Settings │ │
|
||||
│ │ Interval: 10080 min (7 days) [Default] │ │
|
||||
│ │ Pre-Purge: Yes [Default] │ │
|
||||
│ │ Re-Index: Yes [Default] │ │
|
||||
│ ├─────────────────────────────────────────────────────────┤ │
|
||||
│ │ Query: SELECT wo.WADOCO AS Work... [View Full Query] │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ DAILY REFRESH [Enabled] │
|
||||
│ └─ (Same structure as Mass) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ HOURLY REFRESH [Enabled] │
|
||||
│ └─ (Same structure as Mass) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Files to Create
|
||||
|
||||
### Client Project (`src/JdeScoping.Client/`)
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `Pages/Admin/PipelineViewer.razor` | Main page component |
|
||||
| `Components/Admin/PipelineScheduleSection.razor` | Reusable schedule section (Mass/Daily/Hourly) |
|
||||
| `Components/Admin/SqlQueryModal.razor` | Modal for displaying SQL queries/scripts |
|
||||
| `Services/IPipelineConfigService.cs` | Interface for pipeline config access |
|
||||
| `Services/PipelineConfigService.cs` | Implementation - loads pipelines.json |
|
||||
| `Services/IPipelineStatusService.cs` | Interface for execution status |
|
||||
| `Services/PipelineStatusService.cs` | Implementation - calls API for status |
|
||||
| `Models/PipelineScheduleStatus.cs` | View model for schedule status row |
|
||||
| `Models/PipelineExecution.cs` | View model for execution history row |
|
||||
|
||||
### API Project (`src/JdeScoping.Api/`)
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `Controllers/PipelineController.cs` | API endpoints for pipeline config and status |
|
||||
|
||||
### DataSync Project (`src/JdeScoping.DataSync/`)
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `Contracts/IDataUpdateRepository.cs` | Add `GetRecentUpdatesAsync` method |
|
||||
| `Services/DataUpdateRepository.cs` | Implement new method |
|
||||
|
||||
## Data Models
|
||||
|
||||
### View Models (Client)
|
||||
|
||||
```csharp
|
||||
public record PipelineScheduleStatus(
|
||||
UpdateTypes ScheduleType,
|
||||
DateTime? LastSuccessfulRun,
|
||||
DateTime? NextRequiredRun,
|
||||
bool IsOverdue,
|
||||
int IntervalMinutes);
|
||||
|
||||
public record PipelineExecution(
|
||||
UpdateTypes ScheduleType,
|
||||
DateTime StartTime,
|
||||
DateTime? EndTime,
|
||||
TimeSpan Duration,
|
||||
long RecordCount,
|
||||
bool WasSuccessful);
|
||||
```
|
||||
|
||||
### Config Models (reuse or create in Contracts)
|
||||
|
||||
```csharp
|
||||
public record PipelinesRoot(
|
||||
PipelineSettings? Settings,
|
||||
ScheduleDefaults? ScheduleDefaults,
|
||||
Dictionary<string, PipelineConfig> Pipelines);
|
||||
|
||||
public record ScheduleDefaults(
|
||||
ScheduleConfig Mass,
|
||||
ScheduleConfig Daily,
|
||||
ScheduleConfig Hourly);
|
||||
|
||||
public record PipelineConfig(
|
||||
SourceConfig Source,
|
||||
DestinationConfig Destination,
|
||||
PipelineSchedules? Schedules,
|
||||
List<string>? PreScripts,
|
||||
List<string>? PostScripts);
|
||||
|
||||
public record SourceConfig(
|
||||
string Connection,
|
||||
string Query,
|
||||
string? MassQuery,
|
||||
Dictionary<string, ParameterConfig>? Parameters);
|
||||
|
||||
public record ParameterConfig(
|
||||
string Name,
|
||||
string? Format,
|
||||
string? Source);
|
||||
|
||||
public record DestinationConfig(
|
||||
string Table,
|
||||
string[]? MatchColumns,
|
||||
string[]? ExcludeFromUpdate);
|
||||
|
||||
public record PipelineSchedules(
|
||||
ScheduleConfig? Mass,
|
||||
ScheduleConfig? Daily,
|
||||
ScheduleConfig? Hourly);
|
||||
|
||||
public record ScheduleConfig(
|
||||
bool? Enabled,
|
||||
int? IntervalMinutes,
|
||||
bool? PrePurge,
|
||||
bool? ReIndex);
|
||||
```
|
||||
|
||||
## Service Interfaces
|
||||
|
||||
### IPipelineConfigService
|
||||
|
||||
```csharp
|
||||
public interface IPipelineConfigService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the full pipelines configuration.
|
||||
/// </summary>
|
||||
Task<PipelinesRoot> GetPipelinesConfigAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Gets configuration for a specific pipeline.
|
||||
/// </summary>
|
||||
Task<PipelineConfig?> GetPipelineAsync(string pipelineName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets list of all pipeline names (sorted alphabetically).
|
||||
/// </summary>
|
||||
IEnumerable<string> GetPipelineNames();
|
||||
|
||||
/// <summary>
|
||||
/// Gets schedule defaults for computing effective values.
|
||||
/// </summary>
|
||||
ScheduleDefaults GetScheduleDefaults();
|
||||
}
|
||||
```
|
||||
|
||||
### IPipelineStatusService
|
||||
|
||||
```csharp
|
||||
public interface IPipelineStatusService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets schedule status summary for a pipeline (one row per schedule type).
|
||||
/// </summary>
|
||||
Task<List<PipelineScheduleStatus>> GetScheduleStatusAsync(
|
||||
string pipelineName,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets recent execution history for a pipeline.
|
||||
/// </summary>
|
||||
Task<List<PipelineExecution>> GetRecentExecutionsAsync(
|
||||
string pipelineName,
|
||||
int count = 10,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
```
|
||||
|
||||
### IDataUpdateRepository (addition)
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Gets the last N execution records for a specific table.
|
||||
/// </summary>
|
||||
Task<List<DataUpdate>> GetRecentUpdatesAsync(
|
||||
string tableName,
|
||||
int count = 10,
|
||||
CancellationToken cancellationToken = default);
|
||||
```
|
||||
|
||||
## SQL Query Modal Component
|
||||
|
||||
### Features
|
||||
- Large modal (80% viewport width)
|
||||
- Monospace font display (`<pre><code>`)
|
||||
- Basic SQL formatting (line breaks at clauses)
|
||||
- Copy to Clipboard button
|
||||
- Dynamic title based on context
|
||||
|
||||
### Usage
|
||||
```razor
|
||||
<SqlQueryModal @bind-Visible="_showModal"
|
||||
Title="Mass Query - WorkOrder_Curr"
|
||||
Sql="@_selectedSql" />
|
||||
```
|
||||
|
||||
## Schedule Section Component
|
||||
|
||||
### Features
|
||||
- Header with schedule type name and Enabled/Disabled badge
|
||||
- Settings table showing:
|
||||
- Interval (with "Default" or "Override" indicator)
|
||||
- Pre-Purge flag
|
||||
- Re-Index flag
|
||||
- Query preview (truncated to ~100 chars)
|
||||
- "View Full Query" button
|
||||
|
||||
### Props
|
||||
```csharp
|
||||
[Parameter] public string ScheduleType { get; set; } // "Mass", "Daily", "Hourly"
|
||||
[Parameter] public ScheduleConfig? Config { get; set; }
|
||||
[Parameter] public ScheduleConfig DefaultConfig { get; set; }
|
||||
[Parameter] public string? Query { get; set; }
|
||||
[Parameter] public EventCallback<string> OnViewQuery { get; set; }
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Route | Description |
|
||||
|--------|-------|-------------|
|
||||
| GET | `/api/pipelines` | Get all pipeline names |
|
||||
| GET | `/api/pipelines/{name}` | Get pipeline configuration |
|
||||
| GET | `/api/pipelines/{name}/status` | Get schedule status summary |
|
||||
| GET | `/api/pipelines/{name}/executions?count=10` | Get recent executions |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Override Detection
|
||||
To show "Default" vs "Override" for schedule settings:
|
||||
```csharp
|
||||
bool IsOverride(int? pipelineValue, int defaultValue) =>
|
||||
pipelineValue.HasValue && pipelineValue.Value != defaultValue;
|
||||
```
|
||||
|
||||
### Next Required Calculation
|
||||
```csharp
|
||||
DateTime? nextRequired = lastSuccessful?.AddMinutes(intervalMinutes);
|
||||
bool isOverdue = nextRequired.HasValue && nextRequired.Value < DateTime.UtcNow;
|
||||
```
|
||||
|
||||
### Query Truncation
|
||||
```csharp
|
||||
string Truncate(string sql, int maxLength = 100) =>
|
||||
sql.Length <= maxLength ? sql : sql[..maxLength] + "...";
|
||||
```
|
||||
|
||||
### Connection Type Badge Colors
|
||||
- JDE: Blue (`BadgeStyle.Info`)
|
||||
- CMS: Green (`BadgeStyle.Success`)
|
||||
- GIW: Orange (`BadgeStyle.Warning`)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Radzen.Blazor (already installed)
|
||||
- Existing `IDataUpdateRepository`
|
||||
- Existing `pipelines.json` configuration
|
||||
- Existing `UpdateTypes` enum (Hourly, Daily, Mass)
|
||||
Reference in New Issue
Block a user