# v2.0 开发文档

> **版本**: 2.0.0
> **状态**: ✅ 已完成
> **最后更新**: 2025-12-15
> **文档类型**: 技术开发文档

---

## 文档概述

本文档详细记录了书签管理系统 v2.0 的完整技术实现，包括：
- 从 v1.0（本地单用户）到 v2.0（云端多用户）的架构升级
- 后端 API（ASP.NET Core + FreeSql）完整实现
- 前端应用（Vue 3 + TypeScript）技术栈
- 浏览器扩展自动同步机制
- 后台管理系统实现细节

---

## 核心任务完成情况

### ✅ 已完成功能

**后端 API（100%）**
- [x] JWT 认证系统（包含 RefreshToken 机制）
- [x] 用户注册/登录/登出
- [x] 设备自动注册与管理（设备指纹识别）
- [x] 书签 CRUD（含搜索、批量操作、可见性控制）
- [x] 标签管理
- [x] 后台管理接口（用户管理、设备管理、统计数据）

**前端应用（100%）**
- [x] 用户认证界面（登录/注册）
- [x] 书签管理界面（列表、编辑、搜索）
- [x] 设备管理界面
- [x] 可见性控制界面
- [x] Pinia 状态管理（auth、bookmark、device、tag）

**浏览器扩展（90%）**
- [x] 书签自动同步（监听浏览器书签创建事件）
- [x] 文件夹路径转标签
- [x] URL 重复检测
- [x] 同步状态提示
- [ ] 删除/修改同步（预留接口）

**后台管理系统（100%）**
- [x] 仪表盘（系统统计数据）
- [x] 用户管理（列表、详情、禁用、重置密码）
- [x] 设备管理（强制下线、禁用设备）
- [x] 书签管理（查看、删除）

---


## 技术架构变化

###

```mermaid
graph LR
    v1[v1.0_本地单用户]
    v2[v2.0_云端多用户]
    
    v1 -->|架构升级| v2
    
    subgraph v1_arch [v1.0架构]
        fe1[Vue前端]
        idb[IndexedDB]
        ext1[扩展监控]
        fe1 --> idb
        ext1 -.-> fe1
    end
    
    subgraph v2_arch [v2.0架构]
        fe2[Vue前端]
        api[.NET_API]
        db[(SQL数据库)]
        admin[Vue后台]
        ext2[扩展增强]
        
        fe2 --> api
        ext2 --> api
        admin --> api
        api --> db
    end
```

### 技术栈选型

基于用户确认的技术选型：

| 组件 | 技术选择 | 说明 |

|------|---------|------|

| 后端框架 | ASP.NET Core 8 (LTS) | 长期支持版本，稳定可靠 |

| 数据库 | SQL Server / PostgreSQL | 通过 FreeSql 支持多数据库 |

| ORM | FreeSql | 高性能 .NET ORM，支持多数据库、CodeFirst、丰富的查询功能 |

| 认证 | JWT Bearer Token | 无状态认证，支持多设备 |

| 后台管理 | Vue 3 + Element Plus | 与前端技术栈统一 |

| API 文档 | Swagger / OpenAPI | 自动生成接口文档 |

### FreeSql 核心优势

- 支持多种数据库（SQL Server、PostgreSQL、MySQL、Oracle 等）
- CodeFirst 自动同步实体结构到数据库
- 强大的表达式解析引擎，支持复杂查询
- 内置分页、软删除、乐观锁等功能
- Repository + UnitOfWork 模式支持
- 性能优秀，支持批量操作

## 文档结构设计

新文档 `v2.0-开发文档.md` 将包含以下章节：

### 1. 项目概述

- v2.0 产品定位和核心变化
- 从 MVP 到生产级的演进路径
- 多用户、多设备、云同步的业务价值

### 2. 系统架构

**完整架构图**：

```
用户层
├── Bookmark SPA (Vue 3)
├── Browser Extension (Manifest V3)
└── Admin Panel (Vue 3)
         ↓
API 网关层
├── ASP.NET Core 8 Web API
├── JWT 认证中间件
├── 设备识别中间件
└── 可见性过滤中间件
         ↓
业务逻辑层
├── 用户服务 (UserService)
├── 设备服务 (DeviceService)
├── 书签服务 (BookmarkService)
└── 标签服务 (TagService)
         ↓
数据访问层
├── FreeSql IFreeSql 实例
├── Repository 模式
└── UnitOfWork 工作单元
         ↓
数据库层 (SQL Server / PostgreSQL)
```

### 3. 数据模型设计

#### 3.1 核心实体

**Users (用户表)**

```csharp
using FreeSql.DataAnnotations;

[Table(Name = "users")]
public class User
{
    [Column(IsPrimary = true)]
    public Guid Id { get; set; }
    
    [Column(IsNullable = false, StringLength = 200)]
    [Index("idx_user_email", IsUnique = true)]
    public string Email { get; set; }
    
    [Column(IsNullable = false, StringLength = 100)]
    public string UserName { get; set; }
    
    [Column(IsNullable = false, StringLength = 500)]
    public string PasswordHash { get; set; }
    
    [Column(StringLength = 500)]
    public string? Avatar { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc)]
    public DateTime CreatedAt { get; set; }
    
    [Column(IsNullable = true)]
    public DateTime? LastLoginAt { get; set; }
    
    [Column(MapType = typeof(int))]
    public UserStatus Status { get; set; }
    
    // 导航属性
    [Navigate(nameof(Device.UserId))]
    public List<Device> Devices { get; set; }
    
    [Navigate(nameof(Bookmark.UserId))]
    public List<Bookmark> Bookmarks { get; set; }
}

public enum UserStatus
{
    Normal = 0,
    Disabled = 1
}
```

**Devices (设备表)**

```csharp
[Table(Name = "devices")]
public class Device
{
    [Column(IsPrimary = true)]
    public Guid Id { get; set; }
    
    [Column(IsNullable = false)]
    public Guid UserId { get; set; }
    
    [Column(IsNullable = false, StringLength = 200)]
    public string DeviceName { get; set; }
    
    [Column(IsNullable = false, StringLength = 200)]
    public string DeviceType { get; set; }
    
    [Column(IsNullable = false)]
    [Index("idx_device_user_admin")]
    public bool IsAdmin { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc)]
    public DateTime CreatedAt { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc, IsOnUpdateValue = true)]
    public DateTime LastActiveAt { get; set; }
    
    [Column(MapType = typeof(int))]
    public DeviceStatus Status { get; set; }
    
    // 导航属性
    [Navigate(nameof(UserId))]
    public User User { get; set; }
}

public enum DeviceStatus
{
    Normal = 0,
    Disabled = 1
}
```

**Bookmarks (书签表)**

```csharp
[Table(Name = "bookmarks")]
[Index("idx_bookmark_user_order", nameof(UserId), nameof(Order))]
public class Bookmark
{
    [Column(IsPrimary = true)]
    public Guid Id { get; set; }
    
    [Column(IsNullable = false)]
    public Guid UserId { get; set; }
    
    [Column(IsNullable = false, StringLength = 500)]
    public string Title { get; set; }
    
    [Column(IsNullable = false, StringLength = 2000)]
    public string Url { get; set; }
    
    [Column(StringLength = 2000)]
    public string? Description { get; set; }
    
    [Column(StringLength = -1)]  // TEXT/NTEXT
    public string? Icon { get; set; }
    
    [Column(MapType = typeof(string), StringLength = -1)]  // JSON 存储
    public string[] Tags { get; set; }
    
    [Column(IsNullable = false)]
    public int VisitCount { get; set; }
    
    public DateTime? LastVisitTime { get; set; }
    
    [Column(IsNullable = false)]
    public long Order { get; set; }
    
    [Column(MapType = typeof(int))]
    public VisibilityType Visibility { get; set; }
    
    [Column(MapType = typeof(string), StringLength = -1)]  // JSON 存储
    public Guid[]? AllowedDevices { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc)]
    public DateTime CreatedAt { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc, IsOnUpdateValue = true)]
    public DateTime UpdatedAt { get; set; }
    
    // 导航属性
    [Navigate(nameof(UserId))]
    public User User { get; set; }
}

public enum VisibilityType
{
    Public = 0,
    Private = 1,
    Specified = 2
}
```

#### 3.2 数据库索引策略

- Users: Email 唯一索引
- Devices: UserId + IsAdmin 复合索引（用于快速查找管理员设备）
- Bookmarks: UserId + Order 复合索引（列表查询优化）

### 4. FreeSql 配置与使用

#### 4.1 IFreeSql 实例配置

```csharp
// Program.cs
using FreeSql;

var builder = WebApplication.CreateBuilder(args);

// 配置 FreeSql
var freeSqlBuilder = new FreeSqlBuilder()
    .UseConnectionString(GetDataType(), builder.Configuration.GetConnectionString("DefaultConnection"))
    .UseAutoSyncStructure(builder.Environment.IsDevelopment())  // 开发环境自动同步结构
    .UseMonitorCommand(cmd => Console.WriteLine(cmd.CommandText))  // 监控 SQL
    .Build();

// 注册为单例
builder.Services.AddSingleton<IFreeSql>(freeSqlBuilder);

// 辅助方法：根据配置获取数据库类型
DataType GetDataType()
{
    var provider = builder.Configuration["DatabaseProvider"];
    return provider?.ToLower() switch
    {
        "postgresql" => DataType.PostgreSQL,
        "sqlserver" => DataType.SqlServer,
        _ => DataType.SqlServer
    };
}

// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=BookmarkDb;..."
  },
  "DatabaseProvider": "SqlServer"  // 或 "PostgreSQL"
}
```

#### 4.2 Repository 模式

```csharp
// IRepository.cs
public interface IRepository<TEntity> where TEntity : class
{
    ISelect<TEntity> Select { get; }
    Task<TEntity> GetAsync(object id);
    Task<List<TEntity>> GetListAsync();
    Task<TEntity> InsertAsync(TEntity entity);
    Task<int> UpdateAsync(TEntity entity);
    Task<int> DeleteAsync(object id);
}

// 实现
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly IFreeSql _freeSql;
    
    public Repository(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }
    
    public ISelect<TEntity> Select => _freeSql.Select<TEntity>();
    
    public Task<TEntity> GetAsync(object id) 
        => _freeSql.Select<TEntity>().WhereDynamic(id).FirstAsync();
    
    public Task<List<TEntity>> GetListAsync() 
        => _freeSql.Select<TEntity>().ToListAsync();
    
    public Task<TEntity> InsertAsync(TEntity entity) 
        => _freeSql.Insert(entity).ExecuteInsertedAsync();
    
    public Task<int> UpdateAsync(TEntity entity) 
        => _freeSql.Update<TEntity>().SetSource(entity).ExecuteAffrowsAsync();
    
    public Task<int> DeleteAsync(object id) 
        => _freeSql.Delete<TEntity>().WhereDynamic(id).ExecuteAffrowsAsync();
}
```

#### 4.3 UnitOfWork 工作单元

```csharp
// IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
    void BeginTransaction();
    void Commit();
    void Rollback();
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
}

// 实现
public class UnitOfWork : IUnitOfWork
{
    private readonly IFreeSql _freeSql;
    private DbTransaction? _transaction;
    
    public UnitOfWork(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }
    
    public void BeginTransaction()
    {
        _transaction = _freeSql.Ado.BeginTransaction();
    }
    
    public void Commit()
    {
        _transaction?.Commit();
        _transaction?.Dispose();
        _transaction = null;
    }
    
    public void Rollback()
    {
        _transaction?.Rollback();
        _transaction?.Dispose();
        _transaction = null;
    }
    
    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        return new Repository<TEntity>(_freeSql);
    }
    
    public void Dispose()
    {
        _transaction?.Dispose();
    }
}
```

### 5. 后端 API 设计

#### 5.1 RESTful API 规范

**认证接口 (`/api/auth`)**

- `POST /register` - 用户注册
- `POST /login` - 用户登录（返回 JWT + 自动注册设备）
- `POST /logout` - 退出登录
- `POST /refresh` - 刷新 Token
- `POST /password/reset` - 重置密码（P1）

**用户接口 (`/api/user`)**

- `GET /profile` - 获取用户信息
- `PUT /profile` - 更新用户信息

**设备接口 (`/api/devices`)**

- `GET /` - 获取设备列表
- `PUT /{id}` - 更新设备信息（重命名）
- `DELETE /{id}` - 移除设备
- `PUT /{id}/admin` - 设置/取消管理员设备（P1）

**书签接口 (`/api/bookmarks`)**

- `GET /` - 获取书签列表（根据设备可见性自动过滤）
- `POST /` - 新增书签
- `GET /{id}` - 获取书签详情
- `PUT /{id}` - 更新书签
- `DELETE /{id}` - 删除书签
- `PUT /{id}/visibility` - 设置可见性
- `POST /batch` - 批量操作（P1）
- `POST /{id}/visit` - 记录访问

**标签接口 (`/api/tags`)**

- `GET /` - 获取标签列表及统计
- `PUT /{name}` - 重命名标签（P1）
- `DELETE /{name}` - 删除标签（P1）

#### 5.2 可见性过滤实现（FreeSql）

```csharp
// BookmarkService.cs
public async Task<List<Bookmark>> GetUserBookmarksAsync(Guid userId, Guid deviceId, bool isAdminDevice)
{
    var query = _freeSql.Select<Bookmark>()
        .Where(b => b.UserId == userId)
        .Where(b => 
            b.Visibility == VisibilityType.Public ||
            (b.Visibility == VisibilityType.Private && isAdminDevice) ||
            (b.Visibility == VisibilityType.Specified && 
             _freeSql.Select<Bookmark>()
                .Where(x => x.Id == b.Id)
                .Where($"AllowedDevices LIKE '%{deviceId}%'")
                .Any()
            )
        )
        .OrderByDescending(b => b.Order);
    
    return await query.ToListAsync();
}
```

#### 5.3 示例 API Controller

```csharp
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class BookmarksController : ControllerBase
{
    private readonly IFreeSql _freeSql;
    private readonly ILogger<BookmarksController> _logger;
    
    public BookmarksController(IFreeSql freeSql, ILogger<BookmarksController> logger)
    {
        _freeSql = freeSql;
        _logger = logger;
    }
    
    [HttpGet]
    public async Task<ActionResult<List<BookmarkDto>>> GetBookmarks()
    {
        var userId = GetCurrentUserId();
        var deviceId = GetCurrentDeviceId();
        var isAdmin = await IsAdminDeviceAsync(deviceId);
        
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .WhereIf(!isAdmin, b => b.Visibility == VisibilityType.Public)
            .OrderByDescending(b => b.Order)
            .ToListAsync();
        
        return Ok(bookmarks);
    }
    
    [HttpPost]
    public async Task<ActionResult<BookmarkDto>> CreateBookmark([FromBody] CreateBookmarkDto dto)
    {
        var userId = GetCurrentUserId();
        
        var bookmark = new Bookmark
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            Title = dto.Title,
            Url = dto.Url,
            Description = dto.Description,
            Tags = dto.Tags ?? Array.Empty<string>(),
            Visibility = dto.Visibility,
            AllowedDevices = dto.AllowedDevices,
            Order = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
            CreatedAt = DateTime.UtcNow
        };
        
        await _freeSql.Insert(bookmark).ExecuteAffrowsAsync();
        
        return CreatedAtAction(nameof(GetBookmark), new { id = bookmark.Id }, bookmark);
    }
    
    // 其他 API 方法...
}
```

### 6. 前端架构更新

#### 6.1 数据层变化

**v1.0**: IndexedDB (Dexie) → **v2.0**: RESTful API + Axios

**新增服务层**：

- `src/services/api/client.js` - Axios 实例配置（拦截器、Token 注入）
- `src/services/api/authApi.js` - 认证接口封装
- `src/services/api/userApi.js` - 用户接口
- `src/services/api/deviceApi.js` - 设备接口
- `src/services/api/bookmarkApi.js` - 书签接口
- `src/services/api/tagApi.js` - 标签接口
- `src/services/auth/tokenService.js` - JWT Token 管理（localStorage）
- `src/services/auth/deviceService.js` - 设备指纹识别

#### 6.2 Pinia Store 更新

**新增**：

- `stores/auth.js` - 用户认证状态（登录、登出、Token 管理）
- `stores/device.js` - 设备信息（当前设备、是否管理员）

**更新**：

- `stores/links.js` - 从 Dexie 调用改为 API 调用
- `stores/settings.js` - 部分设置迁移到服务器端

#### 6.3 新增功能组件

**用户认证**：

- `components/auth/LoginDialog.vue` - 登录对话框
- `components/auth/RegisterDialog.vue` - 注册对话框
- `components/auth/PasswordResetDialog.vue` - 密码重置（P1）

**设备管理**：

- `components/devices/DeviceList.vue` - 设备列表
- `components/devices/DeviceCard.vue` - 设备卡片
- `components/devices/DeviceManageDialog.vue` - 设备管理对话框

**可见性控制**：

- `components/links/VisibilitySelector.vue` - 可见性选择器
- `components/links/VisibilityBadge.vue` - 可见性徽章

### 7. 浏览器扩展增强

#### 7.1 新增核心功能

**自动同步** (`background/sync.js`):

- 监听 `chrome.bookmarks.onCreated` 事件
- 提取书签信息（标题、URL、图标、文件夹路径）
- 文件夹路径转标签（如：「工作/项目A」→ ["工作", "项目A"]）
- 调用云端 API 保存书签
- 显示同步成功/失败通知

**新标签页替换**:

```json
// manifest.json
{
  "chrome_url_overrides": {
    "newtab": "app/index.html"
  }
}
```

**全局快捷键搜索** (`content/search-overlay.js`):

- Content Script 注入所有页面
- 监听快捷键（Alt+K 或自定义）
- 浮层搜索框（遮罩层 + 搜索输入 + 结果列表）
- 调用 API 实时搜索
- 键盘导航（上下键、回车打开）

**一键收藏** (`popup/quick-save.js`):

- Popup 中的快速收藏表单
- 自动填充当前页标题和 URL
- 可编辑标签、可见性
- 可选择是否同时保存到浏览器书签
- 收藏成功提示

#### 7.2 认证集成

- 使用 `chrome.storage.local` 存储 JWT Token 和设备 ID
- API 请求时自动携带 Token
- Token 过期时自动刷新或提示登录
- 未登录时提示用户登录

### 8. 后台管理系统

#### 8.1 技术栈与项目结构

**技术栈**: Vue 3 + Vite + Vue Router + Pinia + Element Plus + Axios

```
admin-panel/
├── src/
│   ├── views/
│   │   ├── Dashboard.vue          # 仪表盘
│   │   ├── users/
│   │   │   ├── UserList.vue       # 用户列表
│   │   │   └── UserDetail.vue     # 用户详情
│   │   ├── devices/
│   │   │   └── DeviceList.vue     # 设备管理
│   │   └── bookmarks/
│   │       └── BookmarkList.vue   # 书签管理
│   ├── components/
│   ├── stores/
│   │   └── admin.js               # 管理员状态
│   ├── services/
│   │   └── adminApi.js            # 后台 API
│   └── router/
│       └── index.js
├── package.json
└── vite.config.js
```

#### 8.2 核心功能页面

**仪表盘**:

- 关键指标卡片（用户总数、活跃用户、书签总数、设备总数）
- 趋势图表（P2 优先级，使用 ECharts）

**用户管理**:

- 用户列表（分页、搜索、筛选）
- 禁用/启用用户操作
- 查看用户详情（基本信息、设备列表、书签统计）
- 重置密码（P1）

**设备管理**:

- 查看用户的所有设备
- 强制设备下线（P1）
- 禁用设备（P1）

**书签管理**:

- 查看用户的书签列表（分页、搜索）
- 按可见性筛选
- 删除违规书签（P1）

### 9. 数据库迁移与种子数据

#### 9.1 CodeFirst 自动同步

```csharp
// Program.cs
var freeSql = new FreeSqlBuilder()
    .UseConnectionString(dataType, connectionString)
    .UseAutoSyncStructure(true)  // 自动同步实体结构到数据库
    .Build();

// 首次运行时自动创建表和索引
```

#### 9.2 种子数据

```csharp
// 创建超级管理员账号
public static async Task SeedDataAsync(IFreeSql freeSql)
{
    var adminExists = await freeSql.Select<User>()
        .Where(u => u.Email == "admin@bookmarks.local")
        .AnyAsync();
    
    if (!adminExists)
    {
        var admin = new User
        {
            Id = Guid.NewGuid(),
            Email = "admin@bookmarks.local",
            UserName = "Administrator",
            PasswordHash = BCrypt.Net.BCrypt.HashPassword("Admin@123"),
            Status = UserStatus.Normal,
            CreatedAt = DateTime.UtcNow
        };
        
        await freeSql.Insert(admin).ExecuteAffrowsAsync();
    }
}
```

### 10. 开发指南

#### 10.1 环境搭建

**后端环境**:

- .NET 8 SDK
- SQL Server 2019+ 或 PostgreSQL 14+
- Visual Studio 2022 / Rider / VS Code + C# 扩展
- Postman / Swagger UI

**前端环境**:

- Node.js 20+
- npm 8+
- Chrome 90+

#### 10.2 本地开发流程

```bash
# 1. 克隆项目
git clone <repository>

# 2. 后端启动
cd backend-api
dotnet restore
dotnet run
# 首次运行会自动创建数据库表

# 3. 前端启动
cd bookmark-spa
npm install
npm run dev

# 4. 后台管理启动
cd admin-panel
npm install
npm run dev

# 5. 浏览器扩展
cd bookmark-spa
npm run build
cp -r dist/* ../browser-extension/app/
# 在 Chrome 中加载扩展
```

#### 10.3 FreeSql 常用操作示例

```csharp
// 查询
var users = await _freeSql.Select<User>()
    .Where(u => u.Status == UserStatus.Normal)
    .Page(1, 20)
    .ToListAsync();

// 插入
var user = new User { /* ... */ };
await _freeSql.Insert(user).ExecuteAffrowsAsync();

// 更新
await _freeSql.Update<User>()
    .Set(u => u.LastLoginAt, DateTime.UtcNow)
    .Where(u => u.Id == userId)
    .ExecuteAffrowsAsync();

// 删除
await _freeSql.Delete<User>()
    .Where(u => u.Id == userId)
    .ExecuteAffrowsAsync();

// 事务
using var uow = _freeSql.CreateUnitOfWork();
try
{
    var repo = uow.GetRepository<Bookmark>();
    await repo.InsertAsync(bookmark);
    uow.Commit();
}
catch
{
    uow.Rollback();
    throw;
}
```

### 11. 部署指南

#### 11.1 后端部署

**Docker 容器化**:

```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY publish/ .
EXPOSE 80
ENTRYPOINT ["dotnet", "BookmarkApi.dll"]
```

**环境变量**:

- `ConnectionStrings__DefaultConnection`
- `DatabaseProvider` (SqlServer / PostgreSQL)
- `JwtSettings__SecretKey`
- `JwtSettings__Issuer`
- `JwtSettings__Audience`
- `JwtSettings__ExpiryMinutes`

#### 11.2 前端部署

- Bookmark SPA: Nginx / Vercel / Netlify
- Admin Panel: Nginx（需配置访问控制）
- Browser Extension: Chrome Web Store

#### 11.3 数据库部署

- SQL Server: Azure SQL / 自托管
- PostgreSQL: Azure PostgreSQL / AWS RDS / 自托管
- 定期备份策略

### 12. 安全实践

#### 12.1 认证与授权

- 密码使用 BCrypt 或 Argon2 哈希
- JWT Token 有效期设置（1 小时）
- Refresh Token 机制（7 天有效期）
- 设备绑定（Token 包含设备 ID）

#### 12.2 API 安全

- HTTPS 强制传输
- CORS 跨域配置
- 速率限制（ASP.NET Core Rate Limiting）
- FreeSql 自动参数化防止 SQL 注入
- 输入验证和输出编码防止 XSS

### 13. 测试策略

#### 13.1 后端测试

- 单元测试: xUnit + Moq
- FreeSql 内存数据库测试
- API 集成测试: WebApplicationFactory
```csharp
[Fact]
public async Task GetBookmarks_ReturnsUserBookmarks()
{
    // Arrange
    var freeSql = new FreeSqlBuilder()
        .UseConnectionString(DataType.Sqlite, ":memory:")
        .Build();
    
    // Act & Assert
}
```


#### 13.2 前端测试

- 单元测试: Vitest
- E2E 测试: Playwright（包含登录流程）

## v2.0 实际实现情况

### ✅ P0 核心功能（已全部完成）

**后端 API**
- ✅ ASP.NET Core 8 项目搭建
- ✅ FreeSql 配置与实体定义（User、Device、Bookmark、RefreshToken）
- ✅ JWT 认证中间件（包含 RefreshToken 机制）
- ✅ 用户注册/登录 API（含设备自动注册）
- ✅ 书签 CRUD API（含搜索、批量删除、可见性控制）
- ✅ 设备管理 API（重命名、删除、设置管理员）
- ✅ 标签管理 API
- ✅ 后台管理 API（用户管理、设备管理、统计数据）

**前端应用**
- ✅ Vue 3 + TypeScript + Pinia
- ✅ 登录/注册界面
- ✅ JWT Token 管理（自动刷新）
- ✅ 书签列表迁移到 API 调用
- ✅ 设备管理界面
- ✅ 可见性控制界面
- ✅ 全局搜索组件

**浏览器扩展**
- ✅ 用户认证集成
- ✅ Token 存储与管理
- ✅ 书签自动同步（监听 chrome.bookmarks.onCreated）
- ✅ 文件夹路径转标签
- ✅ URL 重复检测
- ✅ 同步状态通知

**后台管理系统**
- ✅ Vue 3 + Element Plus
- ✅ 仪表盘统计（用户数、活跃度、书签数、设备数）
- ✅ 用户管理（列表、详情、禁用/启用、重置密码）
- ✅ 设备管理（查看、强制下线、禁用）
- ✅ 书签管理（查看用户书签、删除）
- ✅ 权限控制（Admin/SuperAdmin）

### 📋 P2-P3 增强功能（v3.0 规划）

**扩展增强**
- 📋 新标签页替换为书签应用
- 📋 全局快捷键搜索（任意页面触发）
- 📋 右键菜单添加书签
- 📋 Popup 快速收藏

**高级功能**
- 📋 统计报表和趋势图
- 📋 标签管理增强（合并、排序）
- 📋 邮箱验证
- 📋 数据导出功能

---

## 已实现的 API 接口清单

### 认证接口 (/api/auth)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| POST | /register | 用户注册 | ✅ |
| POST | /login | 用户登录（含设备注册） | ✅ |
| POST | /logout | 退出登录 | ✅ |
| POST | /refresh | 刷新 Access Token | ✅ |

### 用户接口 (/api/user)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| GET | /profile | 获取用户信息 | ✅ |
| PUT | /profile | 更新用户信息 | ✅ |
| PUT | /password | 修改密码 | ✅ |

### 设备接口 (/api/devices)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| GET | / | 获取设备列表 | ✅ |
| GET | /{id} | 获取设备详情 | ✅ |
| PUT | /{id} | 更新设备名称 | ✅ |
| DELETE | /{id} | 删除设备 | ✅ |
| PUT | /{id}/admin | 设置/取消管理员设备 | ✅ |

### 书签接口 (/api/bookmarks)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| GET | / | 获取书签列表（自动过滤可见性） | ✅ |
| GET | /search | 搜索书签 | ✅ |
| GET | /{id} | 获取书签详情 | ✅ |
| POST | / | 新增书签 | ✅ |
| PUT | /{id} | 更新书签 | ✅ |
| DELETE | /{id} | 删除书签 | ✅ |
| POST | /batch/delete | 批量删除 | ✅ |
| PUT | /{id}/visibility | 设置可见性 | ✅ |
| POST | /{id}/visit | 记录访问 | ✅ |
| PUT | /{id}/order | 更新排序 | ✅ |
| GET | /check-url | 检查 URL 是否存在 | ✅ |
| POST | /import | 导入书签 | ✅ |
| GET | /export | 导出书签 | ✅ |

### 标签接口 (/api/tags)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| GET | / | 获取标签列表及统计 | ✅ |
| PUT | /{name} | 重命名标签 | ✅ |
| DELETE | /{name} | 删除标签 | ✅ |

### 后台管理接口 (/api/admin)

| 方法 | 路径 | 描述 | 状态 |
|------|------|------|------|
| GET | /statistics | 获取系统统计数据 | ✅ |
| GET | /users | 获取用户列表（分页、搜索、筛选） | ✅ |
| GET | /users/{id} | 获取用户详情 | ✅ |
| PUT | /users/{id}/status | 禁用/启用用户 | ✅ |
| POST | /users/{id}/reset-password | 重置用户密码 | ✅ |
| GET | /users/{id}/bookmarks | 获取用户书签列表 | ✅ |
| DELETE | /users/{userId}/bookmarks/{bookmarkId} | 删除用户书签 | ✅ |
| POST | /devices/{id}/force-logout | 强制设备下线 | ✅ |
| PUT | /devices/{id}/status | 禁用/启用设备 | ✅ |

---

## 部署说明

### 环境要求

**后端环境**
- .NET 8 SDK
- SQL Server 2019+ 或 PostgreSQL 14+
- 依赖包：
  - FreeSql (ORM)
  - BCrypt.Net-Next (密码加密)
  - System.IdentityModel.Tokens.Jwt (JWT)
  - Swashbuckle.AspNetCore (API 文档)

**前端环境**
- Node.js 20+
- Vue 3 + TypeScript
- Pinia
- Element Plus

**浏览器扩展**
- Chrome 90+ (Manifest V3)

### 配置说明

**appsettings.json**
```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=BookmarkDb;..."
  },
  "DatabaseProvider": "SqlServer",
  "JwtSettings": {
    "SecretKey": "your-256-bit-secret",
    "Issuer": "BookmarkApi",
    "Audience": "BookmarkClient",
    "ExpiryMinutes": 60,
    "RefreshTokenDays": 7
  }
}
```

---

## 技术亮点

1. **JWT + RefreshToken 双令牌机制**
   - Access Token 有效期 1 小时
   - Refresh Token 有效期 7 天
   - 自动刷新，无感登录体验

2. **设备指纹识别**
   - Canvas 指纹、屏幕分辨率、时区等多因子识别
   - 自动注册设备，支持设备管理
   - 管理员设备机制，灵活权限控制

3. **书签可见性控制**
   - Public：所有设备可见
   - Private：仅管理员设备可见
   - Specified：仅指定设备可见
   - API 层自动过滤，确保数据安全

4. **自动同步机制**
   - 监听浏览器书签事件
   - 文件夹路径自动转标签
   - URL 重复检测
   - 同步状态实时反馈

5. **后台管理系统**
   - 完整的用户管理功能
   - 系统统计数据实时更新
   - 设备管理（强制下线、禁用）
   - 基于角色的权限控制

6. **TypeScript 支持**
   - 前端全面使用 TypeScript
   - 类型安全，减少运行时错误
   - 更好的开发体验和代码维护性

---

## 后续优化建议

1. **性能优化**
   - 实现 Redis 缓存，提高 API 响应速度
   - 添加 CDN 支持前端资源
   - 数据库查询优化和索引优化

2. **功能增强**
   - 实现新标签页替换
   - 添加全局快捷键搜索
   - 支持邮箱验证
   - 实现数据备份和恢复

3. **监控与日志**
   - 添加结构化日志
   - 实现监控告警
   - 错误追踪和性能分析

4. **安全加固**
   - 实现 2FA 双因素认证
   - 添加操作日志审计
   - API 速率限制增强
   - XSS 和 CSRF 防护加强

---

> **v2.0 开发完成时间**: 2025-12-15
>
> **代码位置**: `/src/` 目录
> - 后端: `/src/backend/`
> - 前端: `/src/frontend/`
> - 扩展: `/src/extension/`
> - 后台管理: `/src/admin/`
