HaniBlindBox/.kiro/specs/float-ball-migration/design.md
2026-01-03 21:06:26 +08:00

12 KiB

Design Document: Float Ball Migration

Overview

本设计文档描述悬浮球功能从 PHP 后端迁移到 .NET 10 后端的技术方案。包括数据库表设计、数据迁移脚本、API 接口实现和 Entity Framework 配置。

悬浮球是首页显示的可点击浮动图标,支持两种交互方式:

  1. 展示图片 (type=1): 点击后弹出图片弹窗
  2. 跳转页面 (type=2): 点击后跳转到指定页面

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Frontend (UniApp)                       │
│                   FloatBall.vue Component                    │
└─────────────────────────────────────────────────────────────┘
                              │
                              │ GET /api/getFloatBall
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    HoneyBox.Api Layer                        │
│                   ConfigController.cs                        │
│                  [AllowAnonymous] endpoint                   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   HoneyBox.Core Layer                        │
│                  IFloatBallService.cs                        │
│                   FloatBallService.cs                        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   HoneyBox.Model Layer                       │
│                  FloatBallConfig.cs (Entity)                 │
│                  FloatBallResponse.cs (DTO)                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                     SQL Server                               │
│                  float_ball_configs table                    │
└─────────────────────────────────────────────────────────────┘

Components and Interfaces

1. Database Table: float_ball_configs

CREATE TABLE float_ball_configs (
    id INT IDENTITY(1,1) PRIMARY KEY,
    status TINYINT NOT NULL DEFAULT 0,           -- 状态: 0关闭 1开启
    type TINYINT NOT NULL DEFAULT 1,             -- 类型: 1展示图片 2跳转页面
    image NVARCHAR(255) NOT NULL DEFAULT '',     -- 悬浮球图片URL
    link_url NVARCHAR(255) NOT NULL DEFAULT '',  -- 跳转链接
    position_x NVARCHAR(30) NOT NULL DEFAULT '', -- X轴位置
    position_y NVARCHAR(30) NOT NULL DEFAULT '', -- Y轴位置
    width NVARCHAR(30) NOT NULL DEFAULT '',      -- 宽度
    height NVARCHAR(30) NOT NULL DEFAULT '',     -- 高度
    effect TINYINT NOT NULL DEFAULT 0,           -- 特效: 0无 1缩放动画
    title NVARCHAR(255) NULL,                    -- 标题
    image_details NVARCHAR(255) NULL,            -- 详情图片URL
    image_bj NVARCHAR(255) NULL,                 -- 背景图片URL
    image_details_x NVARCHAR(255) NULL,          -- 详情图片X偏移
    image_details_y NVARCHAR(255) NULL,          -- 详情图片Y偏移
    image_details_w NVARCHAR(255) NULL,          -- 详情图片宽度
    image_details_h NVARCHAR(255) NULL,          -- 详情图片高度
    created_at DATETIME2 NOT NULL DEFAULT GETDATE(),
    updated_at DATETIME2 NOT NULL DEFAULT GETDATE()
);

2. Entity Class: FloatBallConfig

namespace HoneyBox.Model.Entities;

public class FloatBallConfig
{
    public int Id { get; set; }
    public byte Status { get; set; }
    public byte Type { get; set; }
    public string Image { get; set; } = string.Empty;
    public string LinkUrl { get; set; } = string.Empty;
    public string PositionX { get; set; } = string.Empty;
    public string PositionY { get; set; } = string.Empty;
    public string Width { get; set; } = string.Empty;
    public string Height { get; set; } = string.Empty;
    public byte Effect { get; set; }
    public string? Title { get; set; }
    public string? ImageDetails { get; set; }
    public string? ImageBj { get; set; }
    public string? ImageDetailsX { get; set; }
    public string? ImageDetailsY { get; set; }
    public string? ImageDetailsW { get; set; }
    public string? ImageDetailsH { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
}

3. Response DTO: FloatBallResponse

namespace HoneyBox.Model.Models.FloatBall;

public class FloatBallResponse
{
    public int Id { get; set; }
    public int Type { get; set; }
    public string Image { get; set; } = string.Empty;
    public string LinkUrl { get; set; } = string.Empty;
    public string PositionX { get; set; } = string.Empty;
    public string PositionY { get; set; } = string.Empty;
    public string Width { get; set; } = string.Empty;
    public string Height { get; set; } = string.Empty;
    public int Effect { get; set; }
    public string? Title { get; set; }
    public string? ImageDetails { get; set; }
    public string? ImageBj { get; set; }
    public string? ImageDetailsX { get; set; }
    public string? ImageDetailsY { get; set; }
    public string? ImageDetailsW { get; set; }
    public string? ImageDetailsH { get; set; }
}

4. Service Interface: IFloatBallService

namespace HoneyBox.Core.Interfaces;

public interface IFloatBallService
{
    Task<List<FloatBallResponse>> GetEnabledFloatBallsAsync();
}

5. API Endpoint

GET /api/getFloatBall
Authorization: None (AllowAnonymous)
Response: ApiResponse<List<FloatBallResponse>>

Data Models

MySQL Source Table Schema (float_ball_config)

Column Type Description
id int(11) 主键ID
status tinyint(1) 状态: 0关闭 1开启
type tinyint(1) 类型: 1展示图片 2跳转页面
image varchar(255) 悬浮球图片URL
link_url varchar(255) 跳转链接
position_x varchar(30) X轴位置 (如: -0%, 10px)
position_y varchar(30) Y轴位置 (如: 70vh, 21vh)
width varchar(30) 宽度 (如: 150rpx, 52rpx)
height varchar(30) 高度 (如: 165rpx, 120rpx)
effect tinyint(1) 特效: 0无 1缩放动画
create_time int(11) 创建时间 (Unix时间戳)
update_time int(11) 更新时间 (Unix时间戳)
title varchar(255) 标题
image_details varchar(255) 详情图片URL
image_bj varchar(255) 背景图片URL
image_details_x varchar(255) 详情图片X偏移
image_details_y varchar(255) 详情图片Y偏移
image_details_w varchar(255) 详情图片宽度
image_details_h varchar(255) 详情图片高度

Data Migration Mapping

MySQL Column SQL Server Column Transformation
id id 保持原值 (IDENTITY_INSERT ON)
status status 直接映射
type type 直接映射
image image 直接映射
link_url link_url 直接映射
position_x position_x 直接映射
position_y position_y 直接映射
width width 直接映射
height height 直接映射
effect effect 直接映射
title title 直接映射
image_details image_details 直接映射
image_bj image_bj 直接映射
image_details_x image_details_x 直接映射
image_details_y image_details_y 直接映射
image_details_w image_details_w 直接映射
image_details_h image_details_h 直接映射
create_time created_at Unix时间戳 → DATETIME2
update_time updated_at Unix时间戳 → DATETIME2

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: Data Migration Record Count Consistency

For any migration execution, the number of records in SQL Server float_ball_configs table after migration SHALL equal the number of records in MySQL float_ball_config table.

Validates: Requirements 2.4

Property 2: Data Migration ID Preservation

For any record migrated from MySQL to SQL Server, the id value in the target table SHALL equal the id value in the source table.

Validates: Requirements 2.3

Property 3: Timestamp Transformation Validity

For any Unix timestamp value from MySQL, the transformed DATETIME2 value in SQL Server SHALL represent the same point in time.

Validates: Requirements 2.2

Property 4: API Returns Only Enabled Configurations

For any GET request to /api/getFloatBall, all returned configurations SHALL have status equal to 1 (enabled) in the database.

Validates: Requirements 3.1, 3.2

Property 5: API Response Field Completeness

For any configuration returned by the API, the response SHALL contain all required fields (id, type, image, link_url, position_x, position_y, width, height, effect, title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h) and SHALL NOT contain status, created_at, updated_at fields.

Validates: Requirements 3.3, 3.4

Property 6: API Response Format Consistency

For any successful API response, the format SHALL be { "status": 1, "msg": "...", "data": [...] } with status equal to 1.

Validates: Requirements 5.1, 5.2

Property 7: Image URL Preservation

For any configuration with image URLs (image, image_details, image_bj), the API response SHALL return the URLs unchanged from the database values.

Validates: Requirements 5.4

Property 8: Incremental Migration Idempotence

For any migration script execution, running the migration twice SHALL result in the same final state (no duplicate records).

Validates: Requirements 2.5

Error Handling

Migration Script Errors

  1. Connection Failure: Log error and exit with non-zero code
  2. Single Record Insert Failure: Log error, continue with remaining records
  3. Batch Insert Failure: Fall back to single record inserts

API Errors

  1. Database Connection Error: Return { "status": 0, "msg": "获取悬浮球配置失败", "data": null }
  2. Unexpected Exception: Log error, return generic error message

Testing Strategy

Unit Tests

  • Test FloatBallService.GetEnabledFloatBallsAsync() returns only enabled configs
  • Test response DTO mapping excludes status, created_at, updated_at
  • Test empty result when no enabled configs exist

Property-Based Tests

使用 xUnit + FsCheck 进行属性测试:

  1. Property 1: 验证迁移后记录数一致性
  2. Property 4: 验证 API 只返回启用的配置
  3. Property 8: 验证迁移脚本幂等性

Integration Tests

  • Test full API endpoint /api/getFloatBall returns correct format
  • Test migration script with test database

Test Configuration

  • Property tests: 最少 100 次迭代
  • 使用 FsCheck 生成随机测试数据
  • 标签格式: Feature: float-ball-migration, Property {number}: {property_text}