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

7.3 KiB

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:

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:

{
  "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:

{
  "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:

{
  "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

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

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.