Files
invoice-master-poc-v2/docs/dashboard-design-spec.md
Yaojia Wang a564ac9d70 WIP
2026-02-01 18:51:54 +01:00

648 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Dashboard Design Specification
## Overview
Dashboard 是用户进入系统后的第一个页面,用于快速了解:
- 数据标注质量和进度
- 当前模型状态和性能
- 系统最近发生的活动
**目标用户**:使用文档标注系统的客户,需要监控文档处理状态、标注质量和模型训练进度。
---
## 1. UI Layout
### 1.1 Overall Structure
```
+------------------------------------------------------------------+
| Header: Logo + Navigation + User Menu |
+------------------------------------------------------------------+
| |
| Stats Cards Row (4 cards, equal width) |
| |
| +---------------------------+ +------------------------------+ |
| | Data Quality Panel (50%) | | Active Model Panel (50%) | |
| +---------------------------+ +------------------------------+ |
| |
| +--------------------------------------------------------------+ |
| | Recent Activity Panel (full width) | |
| +--------------------------------------------------------------+ |
| |
| +--------------------------------------------------------------+ |
| | System Status Bar (full width) | |
| +--------------------------------------------------------------+ |
+------------------------------------------------------------------+
```
### 1.2 Responsive Breakpoints
| Breakpoint | Layout |
|------------|--------|
| Desktop (>1200px) | 4 cards row, 2-column panels |
| Tablet (768-1200px) | 2x2 cards, 2-column panels |
| Mobile (<768px) | 1 card per row, stacked panels |
---
## 2. Component Specifications
### 2.1 Stats Cards Row
4 个等宽卡片显示核心统计数据
```
+-------------+ +-------------+ +-------------+ +-------------+
| [icon] | | [icon] | | [icon] | | [icon] |
| 38 | | 25 | | 8 | | 5 |
| Total Docs | | Complete | | Incomplete | | Pending |
+-------------+ +-------------+ +-------------+ +-------------+
```
| Card | Icon | Value | Label | Color | Click Action |
|------|------|-------|-------|-------|--------------|
| Total Documents | FileText | `total_documents` | "Total Documents" | Gray | Navigate to Documents page |
| Complete | CheckCircle | `annotation_complete` | "Complete" | Green | Navigate to Documents (filter: complete) |
| Incomplete | AlertCircle | `annotation_incomplete` | "Incomplete" | Orange | Navigate to Documents (filter: incomplete) |
| Pending | Clock | `pending` | "Pending" | Blue | Navigate to Documents (filter: pending) |
**Card Design:**
- Background: White with subtle border
- Icon: 24px, positioned top-left
- Value: 32px bold font
- Label: 14px muted color
- Hover: Slight shadow elevation
- Padding: 16px
### 2.2 Data Quality Panel
左侧面板显示标注完整度和质量指标
```
+---------------------------+
| DATA QUALITY |
| +-----------+ |
| | | |
| | 78% | Annotation |
| | | Complete |
| +-----------+ |
| |
| Complete: 25 |
| Incomplete: 8 |
| Pending: 5 |
| |
| [View Incomplete Docs] |
+---------------------------+
```
**Components:**
| Element | Spec |
|---------|------|
| Title | "DATA QUALITY", 14px uppercase, muted |
| Progress Ring | 120px diameter, stroke width 12px |
| Percentage | 36px bold, centered in ring |
| Label | "Annotation Complete", 14px, below ring |
| Stats List | 14px, icon + label + value per row |
| Action Button | Text button, primary color |
**Progress Ring Colors:**
- Complete portion: Green (#22C55E)
- Remaining: Gray (#E5E7EB)
**Completeness Calculation:**
```
completeness_rate = annotation_complete / (annotation_complete + annotation_incomplete) * 100
```
### 2.3 Active Model Panel
右侧面板显示当前生产模型信息
```
+-------------------------------+
| ACTIVE MODEL |
| |
| v1.2.0 - Invoice Model |
| ----------------------------- |
| |
| mAP Precision Recall |
| 95.1% 94% 92% |
| |
| Activated: 2024-01-20 |
| Documents: 500 |
| |
| [Training] Run-2024-02 [====] |
+-------------------------------+
```
**Components:**
| Element | Spec |
|---------|------|
| Title | "ACTIVE MODEL", 14px uppercase, muted |
| Version + Name | 18px bold (version) + 16px regular (name) |
| Divider | 1px border, full width |
| Metrics Row | 3 columns, equal width |
| Metric Value | 24px bold |
| Metric Label | 12px muted, below value |
| Info Rows | 14px, label: value format |
| Training Indicator | Shows when training is running |
**Metric Colors:**
- mAP >= 90%: Green
- mAP 80-90%: Yellow
- mAP < 80%: Red
**Empty State (No Active Model):**
```
+-------------------------------+
| ACTIVE MODEL |
| |
| [icon: Model] |
| No Active Model |
| |
| Train and activate a |
| model to see stats here |
| |
| [Go to Training] |
+-------------------------------+
```
**Training In Progress:**
```
| Training: Run-2024-02 |
| [=========> ] 45% |
| Started 2 hours ago |
```
### 2.4 Recent Activity Panel
全宽面板显示最近 10 条系统活动
```
+--------------------------------------------------------------+
| RECENT ACTIVITY [See All] |
+--------------------------------------------------------------+
| [rocket] Activated model v1.2.0 2 hours ago|
| [check] Training complete: Run-2024-01, mAP 95.1% yesterday|
| [edit] Modified INV-001.pdf invoice_number yesterday|
| [doc] Uploaded INV-005.pdf 2 days ago|
| [doc] Uploaded INV-004.pdf 2 days ago|
| [x] Training failed: Run-2024-00 3 days ago|
+--------------------------------------------------------------+
```
**Activity Item Layout:**
```
[Icon] [Description] [Timestamp]
```
| Element | Spec |
|---------|------|
| Icon | 16px, color based on type |
| Description | 14px, truncate if too long |
| Timestamp | 12px muted, right-aligned |
| Row Height | 40px |
| Hover | Background highlight |
**Activity Types and Icons:**
| Type | Icon | Color | Description Format |
|------|------|-------|-------------------|
| document_uploaded | FileText | Blue | "Uploaded {filename}" |
| annotation_modified | Edit | Orange | "Modified {filename} {field_name}" |
| training_completed | CheckCircle | Green | "Training complete: {task_name}, mAP {mAP}%" |
| training_failed | XCircle | Red | "Training failed: {task_name}" |
| model_activated | Rocket | Purple | "Activated model {version}" |
**Timestamp Formatting:**
- < 1 minute: "just now"
- < 1 hour: "{n} minutes ago"
- < 24 hours: "{n} hours ago"
- < 7 days: "yesterday" / "{n} days ago"
- >= 7 days: "Jan 15" (date format)
**Empty State:**
```
+--------------------------------------------------------------+
| RECENT ACTIVITY |
| |
| [icon: Activity] |
| No recent activity |
| |
| Start by uploading documents or creating training jobs |
+--------------------------------------------------------------+
```
### 2.5 System Status Bar
底部状态栏,显示系统健康状态。
```
+--------------------------------------------------------------+
| Backend API: [*] Online Database: [*] Connected GPU: [*] Available |
+--------------------------------------------------------------+
```
| Status | Icon | Color |
|--------|------|-------|
| Online/Connected/Available | Filled circle | Green |
| Degraded/Slow | Filled circle | Yellow |
| Offline/Error/Unavailable | Filled circle | Red |
---
## 3. API Endpoints
### 3.1 Dashboard Statistics
```
GET /api/v1/admin/dashboard/stats
```
**Response:**
```json
{
"total_documents": 38,
"annotation_complete": 25,
"annotation_incomplete": 8,
"pending": 5,
"completeness_rate": 75.76
}
```
**Calculation Logic:**
```python
# annotation_complete: labeled documents with core fields
SELECT COUNT(*) FROM admin_documents d
WHERE d.status = 'labeled'
AND EXISTS (
SELECT 1 FROM admin_annotations a
WHERE a.document_id = d.document_id
AND a.class_id IN (0, 3) -- invoice_number OR ocr_number
)
AND EXISTS (
SELECT 1 FROM admin_annotations a
WHERE a.document_id = d.document_id
AND a.class_id IN (4, 5) -- bankgiro OR plusgiro
)
# annotation_incomplete: labeled but missing core fields
SELECT COUNT(*) FROM admin_documents d
WHERE d.status = 'labeled'
AND NOT (/* above conditions */)
# pending: pending + auto_labeling
SELECT COUNT(*) FROM admin_documents
WHERE status IN ('pending', 'auto_labeling')
```
### 3.2 Active Model Info
```
GET /api/v1/admin/dashboard/active-model
```
**Response (with active model):**
```json
{
"model": {
"version_id": "uuid",
"version": "1.2.0",
"name": "Invoice Model",
"metrics_mAP": 0.951,
"metrics_precision": 0.94,
"metrics_recall": 0.92,
"document_count": 500,
"activated_at": "2024-01-20T15:00:00Z"
},
"running_training": {
"task_id": "uuid",
"name": "Run-2024-02",
"status": "running",
"started_at": "2024-01-25T10:00:00Z",
"progress": 45
}
}
```
**Response (no active model):**
```json
{
"model": null,
"running_training": null
}
```
### 3.3 Recent Activity
```
GET /api/v1/admin/dashboard/activity?limit=10
```
**Response:**
```json
{
"activities": [
{
"type": "model_activated",
"description": "Activated model v1.2.0",
"timestamp": "2024-01-25T12:00:00Z",
"metadata": {
"version_id": "uuid",
"version": "1.2.0"
}
},
{
"type": "training_completed",
"description": "Training complete: Run-2024-01, mAP 95.1%",
"timestamp": "2024-01-24T18:30:00Z",
"metadata": {
"task_id": "uuid",
"task_name": "Run-2024-01",
"mAP": 0.951
}
}
]
}
```
**Activity Aggregation Query:**
```sql
-- Union all activity sources, ordered by timestamp DESC, limit 10
(
SELECT 'document_uploaded' as type,
filename as entity_name,
created_at as timestamp,
document_id as entity_id
FROM admin_documents
ORDER BY created_at DESC
LIMIT 10
)
UNION ALL
(
SELECT 'annotation_modified' as type,
-- join to get filename and field name
...
FROM annotation_history
ORDER BY created_at DESC
LIMIT 10
)
UNION ALL
(
SELECT CASE WHEN status = 'completed' THEN 'training_completed'
WHEN status = 'failed' THEN 'training_failed' END as type,
name as entity_name,
completed_at as timestamp,
task_id as entity_id
FROM training_tasks
WHERE status IN ('completed', 'failed')
ORDER BY completed_at DESC
LIMIT 10
)
UNION ALL
(
SELECT 'model_activated' as type,
version as entity_name,
activated_at as timestamp,
version_id as entity_id
FROM model_versions
WHERE activated_at IS NOT NULL
ORDER BY activated_at DESC
LIMIT 10
)
ORDER BY timestamp DESC
LIMIT 10
```
---
## 4. UX Interactions
### 4.1 Loading States
| Component | Loading State |
|-----------|--------------|
| Stats Cards | Skeleton placeholder (gray boxes) |
| Data Quality Ring | Skeleton circle |
| Active Model | Skeleton lines |
| Recent Activity | Skeleton list items (5 rows) |
**Loading Duration Thresholds:**
- < 300ms: No loading state shown
- 300ms - 3s: Show skeleton
- > 3s: Show skeleton + "Taking longer than expected" message
### 4.2 Error States
| Error Type | Display |
|------------|---------|
| API Error | Toast notification + retry button in affected panel |
| Network Error | Full page overlay with retry option |
| Partial Failure | Show available data, error badge on failed sections |
### 4.3 Refresh Behavior
| Trigger | Behavior |
|---------|----------|
| Page Load | Fetch all data |
| Manual Refresh | Button in header, refetch all |
| Auto Refresh | Every 30 seconds for activity panel |
| Focus Return | Refetch if page was hidden > 5 minutes |
### 4.4 Click Actions
| Element | Action |
|---------|--------|
| Total Documents card | Navigate to `/documents` |
| Complete card | Navigate to `/documents?filter=complete` |
| Incomplete card | Navigate to `/documents?filter=incomplete` |
| Pending card | Navigate to `/documents?filter=pending` |
| "View Incomplete Docs" button | Navigate to `/documents?filter=incomplete` |
| Activity item | Navigate to related entity |
| "Go to Training" button | Navigate to `/training` |
| Active Model version | Navigate to `/models/{version_id}` |
### 4.5 Tooltips
| Element | Tooltip Content |
|---------|----------------|
| Completeness % | "25 of 33 labeled documents have complete annotations" |
| mAP metric | "Mean Average Precision at IoU 0.5" |
| Precision metric | "Proportion of correct positive predictions" |
| Recall metric | "Proportion of actual positives correctly identified" |
| Incomplete count | "Documents labeled but missing invoice_number/ocr_number or bankgiro/plusgiro" |
---
## 5. Data Model
### 5.1 TypeScript Types
```typescript
// Dashboard Stats
interface DashboardStats {
total_documents: number;
annotation_complete: number;
annotation_incomplete: number;
pending: number;
completeness_rate: number;
}
// Active Model
interface ActiveModelInfo {
model: ModelVersion | null;
running_training: RunningTraining | null;
}
interface ModelVersion {
version_id: string;
version: string;
name: string;
metrics_mAP: number;
metrics_precision: number;
metrics_recall: number;
document_count: number;
activated_at: string;
}
interface RunningTraining {
task_id: string;
name: string;
status: 'running';
started_at: string;
progress: number;
}
// Activity
interface Activity {
type: ActivityType;
description: string;
timestamp: string;
metadata: Record<string, unknown>;
}
type ActivityType =
| 'document_uploaded'
| 'annotation_modified'
| 'training_completed'
| 'training_failed'
| 'model_activated';
// Activity Response
interface ActivityResponse {
activities: Activity[];
}
```
### 5.2 React Query Hooks
```typescript
// useDashboardStats
const useDashboardStats = () => {
return useQuery({
queryKey: ['dashboard', 'stats'],
queryFn: () => api.get('/admin/dashboard/stats'),
refetchInterval: 30000, // 30 seconds
});
};
// useActiveModel
const useActiveModel = () => {
return useQuery({
queryKey: ['dashboard', 'active-model'],
queryFn: () => api.get('/admin/dashboard/active-model'),
refetchInterval: 60000, // 1 minute
});
};
// useRecentActivity
const useRecentActivity = (limit = 10) => {
return useQuery({
queryKey: ['dashboard', 'activity', limit],
queryFn: () => api.get(`/admin/dashboard/activity?limit=${limit}`),
refetchInterval: 30000,
});
};
```
---
## 6. Annotation Completeness Definition
### 6.1 Core Fields
A document is **complete** when it has annotations for:
| Requirement | Fields | Logic |
|-------------|--------|-------|
| Identifier | `invoice_number` (class_id=0) OR `ocr_number` (class_id=3) | At least one |
| Payment Account | `bankgiro` (class_id=4) OR `plusgiro` (class_id=5) | At least one |
### 6.2 Status Categories
| Category | Criteria |
|----------|----------|
| **Complete** | status=labeled AND has identifier AND has payment account |
| **Incomplete** | status=labeled AND (missing identifier OR missing payment account) |
| **Pending** | status IN (pending, auto_labeling) |
### 6.3 Filter Implementation
```sql
-- Complete documents
WHERE status = 'labeled'
AND document_id IN (
SELECT document_id FROM admin_annotations WHERE class_id IN (0, 3)
)
AND document_id IN (
SELECT document_id FROM admin_annotations WHERE class_id IN (4, 5)
)
-- Incomplete documents
WHERE status = 'labeled'
AND (
document_id NOT IN (
SELECT document_id FROM admin_annotations WHERE class_id IN (0, 3)
)
OR document_id NOT IN (
SELECT document_id FROM admin_annotations WHERE class_id IN (4, 5)
)
)
```
---
## 7. Implementation Checklist
### Backend
- [ ] Create `/api/v1/admin/dashboard/stats` endpoint
- [ ] Create `/api/v1/admin/dashboard/active-model` endpoint
- [ ] Create `/api/v1/admin/dashboard/activity` endpoint
- [ ] Add completeness calculation logic to document repository
- [ ] Implement activity aggregation query
### Frontend
- [ ] Create `DashboardOverview` component
- [ ] Create `StatsCard` component
- [ ] Create `DataQualityPanel` component with progress ring
- [ ] Create `ActiveModelPanel` component
- [ ] Create `RecentActivityPanel` component
- [ ] Create `SystemStatusBar` component
- [ ] Add React Query hooks for dashboard data
- [ ] Implement loading skeletons
- [ ] Implement error states
- [ ] Add navigation actions
- [ ] Add tooltips
### Testing
- [ ] Unit tests for completeness calculation
- [ ] Unit tests for activity aggregation
- [ ] Integration tests for dashboard endpoints
- [ ] E2E tests for dashboard interactions