Files
2025-12-29 10:13:37 +03:00

286 lines
7.3 KiB
Markdown

# Data Model: Migration UI Improvements
**Date**: 2025-12-27 | **Status**: Draft
## Entities
### 1. Task (Extended)
**Source**: `backend/src/core/task_manager.py`
**Fields**:
- `id: UUID` - Unique task identifier
- `type: str` - Task type (e.g., "migration")
- `status: TaskStatus` - Current status (extended enum)
- `start_time: datetime` - When task was created
- `end_time: datetime | None` - When task completed (if applicable)
- `logs: List[LogEntry]` - Task execution logs
- `context: Dict` - Task-specific data
- `input_required: bool` - Whether task is awaiting user input
- `input_request: Dict | None` - Details about required input (for AWAITING_INPUT state)
**New Status Values**:
- `AWAITING_INPUT` - Task is paused waiting for user input (e.g., password)
**Relationships**:
- Has many: `LogEntry`
- Belongs to: `Migration` (if migration task)
**Validation Rules**:
- `id` must be unique and non-null
- `status` must be valid TaskStatus enum value
- `start_time` must be set on creation
- `input_request` required when status is `AWAITING_INPUT`
**State Transitions**:
```mermaid
graph LR
PENDING --> RUNNING
RUNNING --> SUCCESS
RUNNING --> FAILED
RUNNING --> AWAITING_INPUT
AWAITING_INPUT --> RUNNING
AWAITING_INPUT --> FAILED
```
### 2. LogEntry
**Source**: Existing in codebase
**Fields**:
- `timestamp: datetime` - When log entry was created
- `level: str` - Log level (INFO, WARNING, ERROR, etc.)
- `message: str` - Log message
- `context: Dict | None` - Additional context data
**Validation Rules**:
- `timestamp` must be set
- `level` must be valid log level
- `message` must be non-empty
### 3. DatabasePasswordRequest (New)
**Source**: New entity for password prompts
**Fields**:
- `database_name: str` - Name of database requiring password
- `connection_string: str | None` - Partial connection string (without password)
- `error_message: str | None` - Original error message
- `attempt_count: int` - Number of password attempts
**Validation Rules**:
- `database_name` must be non-empty
- `attempt_count` must be >= 0
**Relationships**:
- Embedded in: `Task.input_request`
### 4. TaskListResponse (API DTO)
**Fields**:
- `tasks: List[TaskSummary]` - List of task summaries
- `total: int` - Total number of tasks
- `limit: int` - Pagination limit
- `offset: int` - Pagination offset
### 5. TaskSummary (API DTO)
**Fields**:
- `id: UUID` - Task ID
- `type: str` - Task type
- `status: str` - Current status
- `start_time: datetime` - Start time
- `end_time: datetime | None` - End time (if completed)
- `requires_input: bool` - Whether task needs user input
### 6. TaskLogResponse (API DTO)
**Fields**:
- `task_id: UUID` - Task ID
- `logs: List[LogEntry]` - Task logs
- `status: str` - Current task status
### 7. PasswordPromptRequest (API DTO)
**Fields**:
- `task_id: UUID` - Task ID
- `passwords: Dict[str, str]` - Database name to password mapping
**Validation Rules**:
- `task_id` must exist and be in AWAITING_INPUT state
- All required databases must be provided
## API Contracts
### 1. GET /api/tasks - List Tasks
**Purpose**: Retrieve list of recent migration tasks
**Parameters**:
- `limit: int` (query, optional) - Pagination limit (default: 10)
- `offset: int` (query, optional) - Pagination offset (default: 0)
- `status: str` (query, optional) - Filter by status
**Response**: `TaskListResponse`
**Example**:
```json
{
"tasks": [
{
"id": "abc-123",
"type": "migration",
"status": "RUNNING",
"start_time": "2025-12-27T09:47:12Z",
"end_time": null,
"requires_input": false
}
],
"total": 1,
"limit": 10,
"offset": 0
}
```
### 2. GET /api/tasks/{task_id}/logs - Get Task Logs
**Purpose**: Retrieve detailed logs for a specific task
**Parameters**: None
**Response**: `TaskLogResponse`
**Example**:
```json
{
"task_id": "abc-123",
"status": "AWAITING_INPUT",
"logs": [
{
"timestamp": "2025-12-27T09:47:12Z",
"level": "ERROR",
"message": "Must provide a password for the database",
"context": {
"database": "PostgreSQL"
}
}
]
}
```
### 3. POST /api/tasks/{task_id}/resume - Resume Task with Input
**Purpose**: Provide required input and resume a paused task
**Request Body**: `PasswordPromptRequest`
**Response**:
```json
{
"success": true,
"message": "Task resumed successfully"
}
```
**Error Responses**:
- `404 Not Found` - Task not found
- `400 Bad Request` - Invalid input or task not in AWAITING_INPUT state
- `409 Conflict` - Task already completed or failed
## Database Schema Changes
### Task Persistence (SQLite)
**Table**: `persistent_tasks`
**Columns**:
- `id TEXT PRIMARY KEY` - Task ID
- `status TEXT NOT NULL` - Task status
- `created_at TEXT NOT NULL` - Creation timestamp
- `updated_at TEXT NOT NULL` - Last update timestamp
- `input_request JSON` - Serialized input request data
- `context JSON` - Serialized task context
**Indexes**:
- `idx_status` on `status` column
- `idx_created_at` on `created_at` column
## Event Flow
### Normal Task Execution
```mermaid
sequenceDiagram
participant UI
participant API
participant TaskManager
participant MigrationPlugin
UI->>API: Start migration
API->>TaskManager: Create task
TaskManager->>MigrationPlugin: Execute
MigrationPlugin->>TaskManager: Update status (RUNNING)
MigrationPlugin->>TaskManager: Add logs
MigrationPlugin->>TaskManager: Update status (SUCCESS/FAILED)
```
### Task with Password Requirement
```mermaid
sequenceDiagram
participant UI
participant API
participant TaskManager
participant MigrationPlugin
UI->>API: Start migration
API->>TaskManager: Create task
TaskManager->>MigrationPlugin: Execute
MigrationPlugin->>TaskManager: Update status (RUNNING)
MigrationPlugin->>TaskManager: Detect password error
TaskManager->>TaskManager: Update status (AWAITING_INPUT)
TaskManager->>API: Persist task (if needed)
API->>UI: Task status update
UI->>API: Get task logs
API->>UI: Return logs with error
UI->>User: Show password prompt
User->>UI: Provide password
UI->>API: POST /tasks/{id}/resume
API->>TaskManager: Resume task with password
TaskManager->>MigrationPlugin: Continue execution
MigrationPlugin->>TaskManager: Update status (RUNNING)
MigrationPlugin->>TaskManager: Complete task
```
## Validation Rules
### Task Creation
- Task ID must be unique
- Start time must be set
- Initial status must be PENDING
### Task State Transitions
- Only RUNNING tasks can transition to AWAITING_INPUT
- Only AWAITING_INPUT tasks can be resumed
- Completed tasks (SUCCESS/FAILED) cannot be modified
### Password Input
- All required databases must be provided
- Passwords must meet minimum complexity requirements
- Invalid passwords trigger new error and prompt again
## Implementation Notes
1. **Task Persistence**: Only tasks in AWAITING_INPUT state will be persisted to handle backend restarts
2. **Error Detection**: Specific pattern matching for Superset "Must provide a password" errors
3. **UI Integration**: Real-time updates using existing WebSocket infrastructure
4. **Security**: Passwords are not permanently stored, only used for immediate task resumption
5. **Performance**: Basic pagination for task history to handle growth
## Open Questions
None - All design decisions have been documented and validated against requirements.