This commit is contained in:
西街长安 2025-10-13 17:07:12 +08:00
parent 5ac2a859f0
commit 848e18e057
67 changed files with 8950 additions and 1221 deletions

0
.gitignore vendored Normal file
View File

View File

@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}

View File

@ -0,0 +1,12 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}

View File

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
namespace IM_API.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

30
backend/IM_API/Dockerfile Normal file
View File

@ -0,0 +1,30 @@
# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。
# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
# 此阶段用于生成服务项目
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["IM_API.csproj", "."]
RUN dotnet restore "./IM_API.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./IM_API.csproj" -c $BUILD_CONFIGURATION -o /app/build
# 此阶段用于发布要复制到最终阶段的服务项目
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./IM_API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "IM_API.dll"]

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>3f396849-59bd-435f-a0cb-351ec0559e70</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>http</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,6 @@
@IM_API_HostAddress = http://localhost:5202
GET {{IM_API_HostAddress}}/weatherforecast/
Accept: application/json
###

25
backend/IM_API/IM_API.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36408.4 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IM_API", "IM_API.csproj", "{F001642C-3E66-4C2C-9A25-1AE5EE76CE97}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F001642C-3E66-4C2C-9A25-1AE5EE76CE97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F001642C-3E66-4C2C-9A25-1AE5EE76CE97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F001642C-3E66-4C2C-9A25-1AE5EE76CE97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F001642C-3E66-4C2C-9A25-1AE5EE76CE97}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EC36B0B9-6176-4BC7-BF88-33F923E3E777}
EndGlobalSection
EndGlobal

36
backend/IM_API/Program.cs Normal file
View File

@ -0,0 +1,36 @@
namespace IM_API
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}

View File

@ -0,0 +1,52 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5202"
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7157;http://localhost:5202"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:39786",
"sslPort": 44308
}
}
}

View File

@ -0,0 +1,13 @@
namespace IM_API
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]

View File

@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: Microsoft.Extensions.Configuration.UserSecrets.UserSecretsIdAttribute("3f396849-59bd-435f-a0cb-351ec0559e70")]
[assembly: System.Reflection.AssemblyCompanyAttribute("IM_API")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5ac2a859f072f36c9a26b6a0ae100926ce361737")]
[assembly: System.Reflection.AssemblyProductAttribute("IM_API")]
[assembly: System.Reflection.AssemblyTitleAttribute("IM_API")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// 由 MSBuild WriteCodeFragment 类生成。

View File

@ -0,0 +1 @@
ecdfe90ee262639f8d7c4eb34d36c17cf3984ff8a0ebd0c562bbe56091dd7da2

View File

@ -0,0 +1,21 @@
is_global = true
build_property.TargetFramework = net8.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb = true
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = IM_API
build_property.RootNamespace = IM_API
build_property.ProjectDir = C:\Users\nanxun\Documents\IM\backend\IM_API\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 8.0
build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = C:\Users\nanxun\Documents\IM\backend\IM_API
build_property._RazorSourceGeneratorDebug =
build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity =

View File

@ -0,0 +1,17 @@
// <auto-generated/>
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
global using global::Microsoft.AspNetCore.Http;
global using global::Microsoft.AspNetCore.Routing;
global using global::Microsoft.Extensions.Configuration;
global using global::Microsoft.Extensions.DependencyInjection;
global using global::Microsoft.Extensions.Hosting;
global using global::Microsoft.Extensions.Logging;
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Net.Http.Json;
global using global::System.Threading;
global using global::System.Threading.Tasks;

Binary file not shown.

View File

@ -0,0 +1 @@
{"GlobalPropertiesHash":"CTgS+cWYTbcaEAEp0gp2B6cHTV0srRdQzYydcF2wY5A=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["o/KWD0aNxlAqF51Di\u002BQMhbth5dV2eE0GsWviN/A7C5M=","1Co80OYN1AHERXdYjGVBC4OME7Ab4Ta6mjxvn8WvY5M="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@ -0,0 +1,87 @@
{
"format": 1,
"restore": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj": {}
},
"projects": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"projectName": "IM_API",
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"packagesPath": "C:\\Users\\nanxun\\.nuget\\packages\\",
"outputPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\nanxun\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.300"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets": {
"target": "Package",
"version": "[1.22.1, )"
},
"Swashbuckle.AspNetCore": {
"target": "Package",
"version": "[6.6.2, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.AspNetCore.App": {
"privateAssets": "none"
},
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
}
}
}
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\nanxun\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.1</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\nanxun\.nuget\packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.props" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.props')" />
<Import Project="$(NuGetPackageRoot)swashbuckle.aspnetcore\6.6.2\build\Swashbuckle.AspNetCore.props" Condition="Exists('$(NuGetPackageRoot)swashbuckle.aspnetcore\6.6.2\build\Swashbuckle.AspNetCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.22.1\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.props" Condition="Exists('$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.22.1\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">C:\Users\nanxun\.nuget\packages\microsoft.extensions.apidescription.server\6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
<PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets Condition=" '$(PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets)' == '' ">C:\Users\nanxun\.nuget\packages\microsoft.visualstudio.azure.containers.tools.targets\1.22.1</PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.22.1\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.22.1\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets')" />
</ImportGroup>
</Project>

View File

@ -0,0 +1,620 @@
{
"version": 3,
"targets": {
"net8.0": {
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {
"type": "package",
"build": {
"build/Microsoft.Extensions.ApiDescription.Server.props": {},
"build/Microsoft.Extensions.ApiDescription.Server.targets": {}
},
"buildMultiTargeting": {
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props": {},
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets": {}
}
},
"Microsoft.OpenApi/1.6.14": {
"type": "package",
"compile": {
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
"related": ".pdb;.xml"
}
}
},
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets/1.22.1": {
"type": "package",
"build": {
"build/Microsoft.VisualStudio.Azure.Containers.Tools.Targets.props": {},
"build/Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets": {}
}
},
"Swashbuckle.AspNetCore/6.6.2": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.ApiDescription.Server": "6.0.5",
"Swashbuckle.AspNetCore.Swagger": "6.6.2",
"Swashbuckle.AspNetCore.SwaggerGen": "6.6.2",
"Swashbuckle.AspNetCore.SwaggerUI": "6.6.2"
},
"build": {
"build/Swashbuckle.AspNetCore.props": {}
}
},
"Swashbuckle.AspNetCore.Swagger/6.6.2": {
"type": "package",
"dependencies": {
"Microsoft.OpenApi": "1.6.14"
},
"compile": {
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.dll": {
"related": ".pdb;.xml"
}
},
"frameworkReferences": [
"Microsoft.AspNetCore.App"
]
},
"Swashbuckle.AspNetCore.SwaggerGen/6.6.2": {
"type": "package",
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "6.6.2"
},
"compile": {
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"related": ".pdb;.xml"
}
}
},
"Swashbuckle.AspNetCore.SwaggerUI/6.6.2": {
"type": "package",
"compile": {
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"related": ".pdb;.xml"
}
},
"frameworkReferences": [
"Microsoft.AspNetCore.App"
]
}
}
},
"libraries": {
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {
"sha512": "Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==",
"type": "package",
"path": "microsoft.extensions.apidescription.server/6.0.5",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"build/Microsoft.Extensions.ApiDescription.Server.props",
"build/Microsoft.Extensions.ApiDescription.Server.targets",
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props",
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets",
"microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512",
"microsoft.extensions.apidescription.server.nuspec",
"tools/Newtonsoft.Json.dll",
"tools/dotnet-getdocument.deps.json",
"tools/dotnet-getdocument.dll",
"tools/dotnet-getdocument.runtimeconfig.json",
"tools/net461-x86/GetDocument.Insider.exe",
"tools/net461-x86/GetDocument.Insider.exe.config",
"tools/net461-x86/Microsoft.Win32.Primitives.dll",
"tools/net461-x86/System.AppContext.dll",
"tools/net461-x86/System.Buffers.dll",
"tools/net461-x86/System.Collections.Concurrent.dll",
"tools/net461-x86/System.Collections.NonGeneric.dll",
"tools/net461-x86/System.Collections.Specialized.dll",
"tools/net461-x86/System.Collections.dll",
"tools/net461-x86/System.ComponentModel.EventBasedAsync.dll",
"tools/net461-x86/System.ComponentModel.Primitives.dll",
"tools/net461-x86/System.ComponentModel.TypeConverter.dll",
"tools/net461-x86/System.ComponentModel.dll",
"tools/net461-x86/System.Console.dll",
"tools/net461-x86/System.Data.Common.dll",
"tools/net461-x86/System.Diagnostics.Contracts.dll",
"tools/net461-x86/System.Diagnostics.Debug.dll",
"tools/net461-x86/System.Diagnostics.DiagnosticSource.dll",
"tools/net461-x86/System.Diagnostics.FileVersionInfo.dll",
"tools/net461-x86/System.Diagnostics.Process.dll",
"tools/net461-x86/System.Diagnostics.StackTrace.dll",
"tools/net461-x86/System.Diagnostics.TextWriterTraceListener.dll",
"tools/net461-x86/System.Diagnostics.Tools.dll",
"tools/net461-x86/System.Diagnostics.TraceSource.dll",
"tools/net461-x86/System.Diagnostics.Tracing.dll",
"tools/net461-x86/System.Drawing.Primitives.dll",
"tools/net461-x86/System.Dynamic.Runtime.dll",
"tools/net461-x86/System.Globalization.Calendars.dll",
"tools/net461-x86/System.Globalization.Extensions.dll",
"tools/net461-x86/System.Globalization.dll",
"tools/net461-x86/System.IO.Compression.ZipFile.dll",
"tools/net461-x86/System.IO.Compression.dll",
"tools/net461-x86/System.IO.FileSystem.DriveInfo.dll",
"tools/net461-x86/System.IO.FileSystem.Primitives.dll",
"tools/net461-x86/System.IO.FileSystem.Watcher.dll",
"tools/net461-x86/System.IO.FileSystem.dll",
"tools/net461-x86/System.IO.IsolatedStorage.dll",
"tools/net461-x86/System.IO.MemoryMappedFiles.dll",
"tools/net461-x86/System.IO.Pipes.dll",
"tools/net461-x86/System.IO.UnmanagedMemoryStream.dll",
"tools/net461-x86/System.IO.dll",
"tools/net461-x86/System.Linq.Expressions.dll",
"tools/net461-x86/System.Linq.Parallel.dll",
"tools/net461-x86/System.Linq.Queryable.dll",
"tools/net461-x86/System.Linq.dll",
"tools/net461-x86/System.Memory.dll",
"tools/net461-x86/System.Net.Http.dll",
"tools/net461-x86/System.Net.NameResolution.dll",
"tools/net461-x86/System.Net.NetworkInformation.dll",
"tools/net461-x86/System.Net.Ping.dll",
"tools/net461-x86/System.Net.Primitives.dll",
"tools/net461-x86/System.Net.Requests.dll",
"tools/net461-x86/System.Net.Security.dll",
"tools/net461-x86/System.Net.Sockets.dll",
"tools/net461-x86/System.Net.WebHeaderCollection.dll",
"tools/net461-x86/System.Net.WebSockets.Client.dll",
"tools/net461-x86/System.Net.WebSockets.dll",
"tools/net461-x86/System.Numerics.Vectors.dll",
"tools/net461-x86/System.ObjectModel.dll",
"tools/net461-x86/System.Reflection.Extensions.dll",
"tools/net461-x86/System.Reflection.Primitives.dll",
"tools/net461-x86/System.Reflection.dll",
"tools/net461-x86/System.Resources.Reader.dll",
"tools/net461-x86/System.Resources.ResourceManager.dll",
"tools/net461-x86/System.Resources.Writer.dll",
"tools/net461-x86/System.Runtime.CompilerServices.Unsafe.dll",
"tools/net461-x86/System.Runtime.CompilerServices.VisualC.dll",
"tools/net461-x86/System.Runtime.Extensions.dll",
"tools/net461-x86/System.Runtime.Handles.dll",
"tools/net461-x86/System.Runtime.InteropServices.RuntimeInformation.dll",
"tools/net461-x86/System.Runtime.InteropServices.dll",
"tools/net461-x86/System.Runtime.Numerics.dll",
"tools/net461-x86/System.Runtime.Serialization.Formatters.dll",
"tools/net461-x86/System.Runtime.Serialization.Json.dll",
"tools/net461-x86/System.Runtime.Serialization.Primitives.dll",
"tools/net461-x86/System.Runtime.Serialization.Xml.dll",
"tools/net461-x86/System.Runtime.dll",
"tools/net461-x86/System.Security.Claims.dll",
"tools/net461-x86/System.Security.Cryptography.Algorithms.dll",
"tools/net461-x86/System.Security.Cryptography.Csp.dll",
"tools/net461-x86/System.Security.Cryptography.Encoding.dll",
"tools/net461-x86/System.Security.Cryptography.Primitives.dll",
"tools/net461-x86/System.Security.Cryptography.X509Certificates.dll",
"tools/net461-x86/System.Security.Principal.dll",
"tools/net461-x86/System.Security.SecureString.dll",
"tools/net461-x86/System.Text.Encoding.Extensions.dll",
"tools/net461-x86/System.Text.Encoding.dll",
"tools/net461-x86/System.Text.RegularExpressions.dll",
"tools/net461-x86/System.Threading.Overlapped.dll",
"tools/net461-x86/System.Threading.Tasks.Parallel.dll",
"tools/net461-x86/System.Threading.Tasks.dll",
"tools/net461-x86/System.Threading.Thread.dll",
"tools/net461-x86/System.Threading.ThreadPool.dll",
"tools/net461-x86/System.Threading.Timer.dll",
"tools/net461-x86/System.Threading.dll",
"tools/net461-x86/System.ValueTuple.dll",
"tools/net461-x86/System.Xml.ReaderWriter.dll",
"tools/net461-x86/System.Xml.XDocument.dll",
"tools/net461-x86/System.Xml.XPath.XDocument.dll",
"tools/net461-x86/System.Xml.XPath.dll",
"tools/net461-x86/System.Xml.XmlDocument.dll",
"tools/net461-x86/System.Xml.XmlSerializer.dll",
"tools/net461-x86/netstandard.dll",
"tools/net461/GetDocument.Insider.exe",
"tools/net461/GetDocument.Insider.exe.config",
"tools/net461/Microsoft.Win32.Primitives.dll",
"tools/net461/System.AppContext.dll",
"tools/net461/System.Buffers.dll",
"tools/net461/System.Collections.Concurrent.dll",
"tools/net461/System.Collections.NonGeneric.dll",
"tools/net461/System.Collections.Specialized.dll",
"tools/net461/System.Collections.dll",
"tools/net461/System.ComponentModel.EventBasedAsync.dll",
"tools/net461/System.ComponentModel.Primitives.dll",
"tools/net461/System.ComponentModel.TypeConverter.dll",
"tools/net461/System.ComponentModel.dll",
"tools/net461/System.Console.dll",
"tools/net461/System.Data.Common.dll",
"tools/net461/System.Diagnostics.Contracts.dll",
"tools/net461/System.Diagnostics.Debug.dll",
"tools/net461/System.Diagnostics.DiagnosticSource.dll",
"tools/net461/System.Diagnostics.FileVersionInfo.dll",
"tools/net461/System.Diagnostics.Process.dll",
"tools/net461/System.Diagnostics.StackTrace.dll",
"tools/net461/System.Diagnostics.TextWriterTraceListener.dll",
"tools/net461/System.Diagnostics.Tools.dll",
"tools/net461/System.Diagnostics.TraceSource.dll",
"tools/net461/System.Diagnostics.Tracing.dll",
"tools/net461/System.Drawing.Primitives.dll",
"tools/net461/System.Dynamic.Runtime.dll",
"tools/net461/System.Globalization.Calendars.dll",
"tools/net461/System.Globalization.Extensions.dll",
"tools/net461/System.Globalization.dll",
"tools/net461/System.IO.Compression.ZipFile.dll",
"tools/net461/System.IO.Compression.dll",
"tools/net461/System.IO.FileSystem.DriveInfo.dll",
"tools/net461/System.IO.FileSystem.Primitives.dll",
"tools/net461/System.IO.FileSystem.Watcher.dll",
"tools/net461/System.IO.FileSystem.dll",
"tools/net461/System.IO.IsolatedStorage.dll",
"tools/net461/System.IO.MemoryMappedFiles.dll",
"tools/net461/System.IO.Pipes.dll",
"tools/net461/System.IO.UnmanagedMemoryStream.dll",
"tools/net461/System.IO.dll",
"tools/net461/System.Linq.Expressions.dll",
"tools/net461/System.Linq.Parallel.dll",
"tools/net461/System.Linq.Queryable.dll",
"tools/net461/System.Linq.dll",
"tools/net461/System.Memory.dll",
"tools/net461/System.Net.Http.dll",
"tools/net461/System.Net.NameResolution.dll",
"tools/net461/System.Net.NetworkInformation.dll",
"tools/net461/System.Net.Ping.dll",
"tools/net461/System.Net.Primitives.dll",
"tools/net461/System.Net.Requests.dll",
"tools/net461/System.Net.Security.dll",
"tools/net461/System.Net.Sockets.dll",
"tools/net461/System.Net.WebHeaderCollection.dll",
"tools/net461/System.Net.WebSockets.Client.dll",
"tools/net461/System.Net.WebSockets.dll",
"tools/net461/System.Numerics.Vectors.dll",
"tools/net461/System.ObjectModel.dll",
"tools/net461/System.Reflection.Extensions.dll",
"tools/net461/System.Reflection.Primitives.dll",
"tools/net461/System.Reflection.dll",
"tools/net461/System.Resources.Reader.dll",
"tools/net461/System.Resources.ResourceManager.dll",
"tools/net461/System.Resources.Writer.dll",
"tools/net461/System.Runtime.CompilerServices.Unsafe.dll",
"tools/net461/System.Runtime.CompilerServices.VisualC.dll",
"tools/net461/System.Runtime.Extensions.dll",
"tools/net461/System.Runtime.Handles.dll",
"tools/net461/System.Runtime.InteropServices.RuntimeInformation.dll",
"tools/net461/System.Runtime.InteropServices.dll",
"tools/net461/System.Runtime.Numerics.dll",
"tools/net461/System.Runtime.Serialization.Formatters.dll",
"tools/net461/System.Runtime.Serialization.Json.dll",
"tools/net461/System.Runtime.Serialization.Primitives.dll",
"tools/net461/System.Runtime.Serialization.Xml.dll",
"tools/net461/System.Runtime.dll",
"tools/net461/System.Security.Claims.dll",
"tools/net461/System.Security.Cryptography.Algorithms.dll",
"tools/net461/System.Security.Cryptography.Csp.dll",
"tools/net461/System.Security.Cryptography.Encoding.dll",
"tools/net461/System.Security.Cryptography.Primitives.dll",
"tools/net461/System.Security.Cryptography.X509Certificates.dll",
"tools/net461/System.Security.Principal.dll",
"tools/net461/System.Security.SecureString.dll",
"tools/net461/System.Text.Encoding.Extensions.dll",
"tools/net461/System.Text.Encoding.dll",
"tools/net461/System.Text.RegularExpressions.dll",
"tools/net461/System.Threading.Overlapped.dll",
"tools/net461/System.Threading.Tasks.Parallel.dll",
"tools/net461/System.Threading.Tasks.dll",
"tools/net461/System.Threading.Thread.dll",
"tools/net461/System.Threading.ThreadPool.dll",
"tools/net461/System.Threading.Timer.dll",
"tools/net461/System.Threading.dll",
"tools/net461/System.ValueTuple.dll",
"tools/net461/System.Xml.ReaderWriter.dll",
"tools/net461/System.Xml.XDocument.dll",
"tools/net461/System.Xml.XPath.XDocument.dll",
"tools/net461/System.Xml.XPath.dll",
"tools/net461/System.Xml.XmlDocument.dll",
"tools/net461/System.Xml.XmlSerializer.dll",
"tools/net461/netstandard.dll",
"tools/netcoreapp2.1/GetDocument.Insider.deps.json",
"tools/netcoreapp2.1/GetDocument.Insider.dll",
"tools/netcoreapp2.1/GetDocument.Insider.runtimeconfig.json",
"tools/netcoreapp2.1/System.Diagnostics.DiagnosticSource.dll"
]
},
"Microsoft.OpenApi/1.6.14": {
"sha512": "tTaBT8qjk3xINfESyOPE2rIellPvB7qpVqiWiyA/lACVvz+xOGiXhFUfohcx82NLbi5avzLW0lx+s6oAqQijfw==",
"type": "package",
"path": "microsoft.openapi/1.6.14",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/netstandard2.0/Microsoft.OpenApi.dll",
"lib/netstandard2.0/Microsoft.OpenApi.pdb",
"lib/netstandard2.0/Microsoft.OpenApi.xml",
"microsoft.openapi.1.6.14.nupkg.sha512",
"microsoft.openapi.nuspec"
]
},
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets/1.22.1": {
"sha512": "EfYANhAWqmWKoLwN6bxoiPZSOfJSO9lzX+UrU6GVhLhPub1Hd+5f0zL0/tggIA6mRz6Ebw2xCNcIsM4k+7NPng==",
"type": "package",
"path": "microsoft.visualstudio.azure.containers.tools.targets/1.22.1",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"CHANGELOG.md",
"EULA.md",
"ThirdPartyNotices.txt",
"build/Container.props",
"build/Container.targets",
"build/Microsoft.VisualStudio.Azure.Containers.Tools.Targets.props",
"build/Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets",
"build/Rules/GeneralBrowseObject.xaml",
"build/Rules/cs-CZ/GeneralBrowseObject.xaml",
"build/Rules/de-DE/GeneralBrowseObject.xaml",
"build/Rules/es-ES/GeneralBrowseObject.xaml",
"build/Rules/fr-FR/GeneralBrowseObject.xaml",
"build/Rules/it-IT/GeneralBrowseObject.xaml",
"build/Rules/ja-JP/GeneralBrowseObject.xaml",
"build/Rules/ko-KR/GeneralBrowseObject.xaml",
"build/Rules/pl-PL/GeneralBrowseObject.xaml",
"build/Rules/pt-BR/GeneralBrowseObject.xaml",
"build/Rules/ru-RU/GeneralBrowseObject.xaml",
"build/Rules/tr-TR/GeneralBrowseObject.xaml",
"build/Rules/zh-CN/GeneralBrowseObject.xaml",
"build/Rules/zh-TW/GeneralBrowseObject.xaml",
"build/ToolsTarget.props",
"build/ToolsTarget.targets",
"icon.png",
"microsoft.visualstudio.azure.containers.tools.targets.1.22.1.nupkg.sha512",
"microsoft.visualstudio.azure.containers.tools.targets.nuspec",
"tools/Microsoft.VisualStudio.Containers.Tools.Common.dll",
"tools/Microsoft.VisualStudio.Containers.Tools.Shared.dll",
"tools/Microsoft.VisualStudio.Containers.Tools.Tasks.dll",
"tools/Newtonsoft.Json.dll",
"tools/System.Security.Principal.Windows.dll",
"tools/cs/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/cs/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/cs/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/de/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/de/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/de/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/es/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/es/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/es/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/fr/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/fr/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/fr/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/it/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/it/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/it/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/ja/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/ja/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/ja/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/ko/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/ko/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/ko/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/pl/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/pl/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/pl/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/pt-BR/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/pt-BR/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/pt-BR/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/ru/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/ru/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/ru/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/tr/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/tr/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/tr/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/zh-Hans/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/zh-Hans/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/zh-Hans/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll",
"tools/zh-Hant/Microsoft.VisualStudio.Containers.Tools.Common.resources.dll",
"tools/zh-Hant/Microsoft.VisualStudio.Containers.Tools.Shared.resources.dll",
"tools/zh-Hant/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll"
]
},
"Swashbuckle.AspNetCore/6.6.2": {
"sha512": "+NB4UYVYN6AhDSjW0IJAd1AGD8V33gemFNLPaxKTtPkHB+HaKAKf9MGAEUPivEWvqeQfcKIw8lJaHq6LHljRuw==",
"type": "package",
"path": "swashbuckle.aspnetcore/6.6.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"build/Swashbuckle.AspNetCore.props",
"swashbuckle.aspnetcore.6.6.2.nupkg.sha512",
"swashbuckle.aspnetcore.nuspec"
]
},
"Swashbuckle.AspNetCore.Swagger/6.6.2": {
"sha512": "ovgPTSYX83UrQUWiS5vzDcJ8TEX1MAxBgDFMK45rC24MorHEPQlZAHlaXj/yth4Zf6xcktpUgTEBvffRQVwDKA==",
"type": "package",
"path": "swashbuckle.aspnetcore.swagger/6.6.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net5.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net5.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net5.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/net6.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net6.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net6.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/net7.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net7.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net7.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swagger.6.6.2.nupkg.sha512",
"swashbuckle.aspnetcore.swagger.nuspec"
]
},
"Swashbuckle.AspNetCore.SwaggerGen/6.6.2": {
"sha512": "zv4ikn4AT1VYuOsDCpktLq4QDq08e7Utzbir86M5/ZkRaLXbCPF11E1/vTmOiDzRTl0zTZINQU2qLKwTcHgfrA==",
"type": "package",
"path": "swashbuckle.aspnetcore.swaggergen/6.6.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swaggergen.6.6.2.nupkg.sha512",
"swashbuckle.aspnetcore.swaggergen.nuspec"
]
},
"Swashbuckle.AspNetCore.SwaggerUI/6.6.2": {
"sha512": "mBBb+/8Hm2Q3Wygag+hu2jj69tZW5psuv0vMRXY07Wy+Rrj40vRP8ZTbKBhs91r45/HXT4aY4z0iSBYx1h6JvA==",
"type": "package",
"path": "swashbuckle.aspnetcore.swaggerui/6.6.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net5.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net7.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swaggerui.6.6.2.nupkg.sha512",
"swashbuckle.aspnetcore.swaggerui.nuspec"
]
}
},
"projectFileDependencyGroups": {
"net8.0": [
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets >= 1.22.1",
"Swashbuckle.AspNetCore >= 6.6.2"
]
},
"packageFolders": {
"C:\\Users\\nanxun\\.nuget\\packages\\": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"projectName": "IM_API",
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"packagesPath": "C:\\Users\\nanxun\\.nuget\\packages\\",
"outputPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\nanxun\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.300"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets": {
"target": "Package",
"version": "[1.22.1, )"
},
"Swashbuckle.AspNetCore": {
"target": "Package",
"version": "[6.6.2, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.AspNetCore.App": {
"privateAssets": "none"
},
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
}
}
}
}

View File

@ -0,0 +1,16 @@
{
"version": 2,
"dgSpecHash": "sPkaomFyhxE=",
"success": true,
"projectFilePath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"expectedPackageFiles": [
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.apidescription.server\\6.0.5\\microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.openapi\\1.6.14\\microsoft.openapi.1.6.14.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.visualstudio.azure.containers.tools.targets\\1.22.1\\microsoft.visualstudio.azure.containers.tools.targets.1.22.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore\\6.6.2\\swashbuckle.aspnetcore.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swagger\\6.6.2\\swashbuckle.aspnetcore.swagger.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swaggergen\\6.6.2\\swashbuckle.aspnetcore.swaggergen.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swaggerui\\6.6.2\\swashbuckle.aspnetcore.swaggerui.6.6.2.nupkg.sha512"
],
"logs": []
}

View File

@ -1,141 +1,141 @@
# IM 系统消息存储与推送策略文档
## 1. 概述
本策略文档定义了 **消息在系统中的存储、读取和推送流程**,目标是:
- 保证 **消息实时性**
- 支持 **离线消息存储与同步**
- 支持 **多端登录同步**
- 支持 **单聊、群聊及系统消息**
------
## 2. 消息存储策略
### 2.1 消息表设计
表结构参考前期设计:
| 表名 | 作用 |
| ------------ | ------------------------------------------------------------ |
| Messages | 存储所有聊天消息(单聊/群聊) |
| Conversation | 缓存用户最近会话信息last_message_id, target_id, unread_count |
| Files | 附件 / 图片 / 语音存储URL |
------
### 2.2 消息存储规则
1. **单聊消息**
- 写入 `Messages`
- 更新发送者和接收者 `Conversation`
- 更新 `UnreadCount`
2. **群聊消息**
- 写入 `Messages`
- 更新群成员对应的 `Conversation`except 发送者)
- 更新每个成员的 `UnreadCount`
3. **文件消息**
- 文件存储到对象存储OSS/S3/MinIO
- `Messages.Content` 存文件 URL + metadata
4. **消息撤回**
- 消息允许撤回时,修改 `message.status = 1
- 更新 `Conversation.LastMessageId`(如撤回的是最后一条消息)
------
## 3. 消息推送策略
### 3.1 推送原则
- **实时性**:在线用户立即通过 WebSocket 推送
- **可靠性**:离线用户存储消息,登录时同步
- **顺序保证**:消息按 `timestamp``messageId` 顺序发送
- **幂等性**:客户端可根据 `messageId` 去重
------
### 3.2 单聊推送流程
1. 发送者通过 WebSocket 或 HTTP API 发送消息
2. 服务端写入 `Messages`
3. 查询接收者是否在线
- **在线**:通过 WebSocket 推送
- **离线**:存储到 Redis 或 `Conversation.UnreadCount`
4. 接收者收到消息后发送 `MESSAGE_ACK`
5. //暂不要求:更新消息状态(已送达 / 已读)
------
### 3.3 群聊推送流程
1. 发送者发送群消息
2. 服务端写入 `Message`s 表
3. 查询群成员列表(`GroupMember` 表)
4. 遍历成员:
- **在线成员**WebSocket 推送
- **离线成员**:增加 `UnreadCount`,保存在 Redis/数据库
5. //暂不要求:接收者回 ACK 后更新 `message_receipt`(已读)
------
### 3.4 离线消息处理
- 离线消息存储位置:
1. 数据库 `Messages` 表(长期保存)
2. Redis 缓存(短期加速推送)
- 客户端上线时:
1. 请求 `/syncMessages` 接口
2. 返回未读消息 + 未读计数
- 消息同步完成后清除缓存或更新状态
------
### 3.5 多端同步策略
- 每个设备维护独立的 `deviceId`
- WebSocket 推送时:
- 排除发送设备
- 推送给同账号其他设备
- //暂不要求:消息回执:
- 每端发送 ACK
- 服务端更新 `Voncers``message_receipt`
------
## 4. 消息可靠性保障
| 场景 | 解决方案 |
| ------------------ | ---------------------------------- |
| 消息丢失 | 发送端生成 `requestId`,服务端去重 |
| 消息顺序错乱 | 按 `messageId``timestamp` 排序 |
| WebSocket 异常断开 | 客户端重连后同步离线消息 |
| 群聊大消息量 | 异步推送 + 批量 ACK |
------
## 5. //暂不要求:高性能优化策略
1. **消息表索引**`(chat_type, to_id, created_at)`
2. **会话表缓存**`conversation` 表避免全表查询
3. **Redis 缓存**:用户在线状态、未读消息数
4. **分表/分库**:按月或按用户分表
5. **异步推送队列**:消息通过 MQKafka/RabbitMQ推送保证高并发
------
## 6. 消息撤回与删除策略
1. **撤回条件**:超时限制( 2 分钟内可撤回)
2. **撤回操作**
- 更新 `message.status = 1`
- 更新 `Conversation.LastMessageId`
- 推送撤回事件到在线用户
------
## 7. 系统消息与通知策略
- 系统消息(好友申请、群邀请、公告)走 **同样的消息推送流程**
- 保留在 `Notification`
# IM 系统消息存储与推送策略文档
## 1. 概述
本策略文档定义了 **消息在系统中的存储、读取和推送流程**,目标是:
- 保证 **消息实时性**
- 支持 **离线消息存储与同步**
- 支持 **多端登录同步**
- 支持 **单聊、群聊及系统消息**
------
## 2. 消息存储策略
### 2.1 消息表设计
表结构参考前期设计:
| 表名 | 作用 |
| ------------ | ------------------------------------------------------------ |
| Messages | 存储所有聊天消息(单聊/群聊) |
| Conversation | 缓存用户最近会话信息last_message_id, target_id, unread_count |
| Files | 附件 / 图片 / 语音存储URL |
------
### 2.2 消息存储规则
1. **单聊消息**
- 写入 `Messages`
- 更新发送者和接收者 `Conversation`
- 更新 `UnreadCount`
2. **群聊消息**
- 写入 `Messages`
- 更新群成员对应的 `Conversation`except 发送者)
- 更新每个成员的 `UnreadCount`
3. **文件消息**
- 文件存储到对象存储OSS/S3/MinIO
- `Messages.Content` 存文件 URL + metadata
4. **消息撤回**
- 消息允许撤回时,修改 `message.status = 1
- 更新 `Conversation.LastMessageId`(如撤回的是最后一条消息)
------
## 3. 消息推送策略
### 3.1 推送原则
- **实时性**:在线用户立即通过 WebSocket 推送
- **可靠性**:离线用户存储消息,登录时同步
- **顺序保证**:消息按 `timestamp``messageId` 顺序发送
- **幂等性**:客户端可根据 `messageId` 去重
------
### 3.2 单聊推送流程
1. 发送者通过 WebSocket 或 HTTP API 发送消息
2. 服务端写入 `Messages`
3. 查询接收者是否在线
- **在线**:通过 WebSocket 推送
- **离线**:存储到 Redis 或 `Conversation.UnreadCount`
4. 接收者收到消息后发送 `MESSAGE_ACK`
5. //暂不要求:更新消息状态(已送达 / 已读)
------
### 3.3 群聊推送流程
1. 发送者发送群消息
2. 服务端写入 `Message`s 表
3. 查询群成员列表(`GroupMember` 表)
4. 遍历成员:
- **在线成员**WebSocket 推送
- **离线成员**:增加 `UnreadCount`,保存在 Redis/数据库
5. //暂不要求:接收者回 ACK 后更新 `message_receipt`(已读)
------
### 3.4 离线消息处理
- 离线消息存储位置:
1. 数据库 `Messages` 表(长期保存)
2. Redis 缓存(短期加速推送)
- 客户端上线时:
1. 请求 `/syncMessages` 接口
2. 返回未读消息 + 未读计数
- 消息同步完成后清除缓存或更新状态
------
### 3.5 多端同步策略
- 每个设备维护独立的 `deviceId`
- WebSocket 推送时:
- 排除发送设备
- 推送给同账号其他设备
- //暂不要求:消息回执:
- 每端发送 ACK
- 服务端更新 `Voncers``message_receipt`
------
## 4. 消息可靠性保障
| 场景 | 解决方案 |
| ------------------ | ---------------------------------- |
| 消息丢失 | 发送端生成 `requestId`,服务端去重 |
| 消息顺序错乱 | 按 `messageId``timestamp` 排序 |
| WebSocket 异常断开 | 客户端重连后同步离线消息 |
| 群聊大消息量 | 异步推送 + 批量 ACK |
------
## 5. //暂不要求:高性能优化策略
1. **消息表索引**`(chat_type, to_id, created_at)`
2. **会话表缓存**`conversation` 表避免全表查询
3. **Redis 缓存**:用户在线状态、未读消息数
4. **分表/分库**:按月或按用户分表
5. **异步推送队列**:消息通过 MQKafka/RabbitMQ推送保证高并发
------
## 6. 消息撤回与删除策略
1. **撤回条件**:超时限制( 2 分钟内可撤回)
2. **撤回操作**
- 更新 `message.status = 1`
- 更新 `Conversation.LastMessageId`
- 推送撤回事件到在线用户
------
## 7. 系统消息与通知策略
- 系统消息(好友申请、群邀请、公告)走 **同样的消息推送流程**
- 保留在 `Notification`
- 支持离线同步

View File

@ -1,115 +1,115 @@
# IM 系统鉴权与 Token 安全规范文档
## 1. 概述
本规范用于确保系统用户身份验证、消息安全和多端同步安全。
鉴权体系采用 **TokenJWT 或自定义) + HTTPS/WebSocket** 方式。
------
## 2. 鉴权方式选择
| 方法 |
| -------------------------------------- |
| JWTJSON Web Token+ Redis黑名单机制 |
------
## 3. Token 生成规则
### 3.1 Token 内容结构JWT 示例)
```
{
"userId": 1001, // 用户ID
"iat": 1700000000, // 签发时间Unix时间戳
"exp": 1700003600, // 过期时间
"deviceId": "uuid-xxxx", // 设备ID用于多端区分
"role": "user" // 角色
}
```
- **签名算法**HMAC-SHA256 或 RSA
- **签名秘钥**:服务端统一管理,不暴露给客户端
------
### 3.2 Token 生成流程
1. 用户登录(用户名/密码)
2. 验证用户名与密码正确
3. 生成 Token写入 Redis可选
4. 返回 Token 给客户端
**响应示例**
```
{
"code": 0,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
```
------
## 4. Token 使用
### 4.1 HTTP 接口鉴权
- 客户端请求带上 Header
```
Authorization: Bearer <token>
```
- 后端解析 Token
1. 校验签名
2. 校验 exp 是否过期
3. 校验 Redis 黑名单(可选)
- 不通过返回 401 / code 1006
------
### 4.2 WebSocket 鉴权
- 建立连接时通过 Query 或 Header 传 Token
```
ws://example.com/ws?token=xxxx&deviceId=uuid-001
```
- 握手阶段:
1. 服务器验证 Token
2. 成功返回 AUTH_SUCCESS
3. 失败返回 AUTH_FAIL 并关闭连接
------
## 5. Token 过期策略
| 类型 | 建议值 | 说明 |
| ------------------ | ---------------------- | ---------------------------------------- |
| 短期 Token | 30 分钟 ~ 1 小时 | 防止长时间泄露 |
| 长期 Refresh Token | 7 ~ 30 天 | 用于获取新 Token安全性高 |
| WebSocket 长连接 | Token 与短期有效期一致 | 客户端定期刷新 Token心跳或重连时验证 |
### 5.1 Token 刷新流程
1. 客户端 Token 快过期时,调用刷新接口
2. 服务端验证 Refresh Token
3. 返回新 Token更新 Redis / 黑名单
------
## 6. 多端登录处理
- **每个设备对应一个 deviceId**
- Token 中绑定 deviceId
- 多端策略:
1. **允许多端同时登录**:每端单独维护 Token
2. **限制单端登录**:新登录覆盖旧设备 Token
3. **设备列表管理**:可查看在线设备并强制下线
# IM 系统鉴权与 Token 安全规范文档
## 1. 概述
本规范用于确保系统用户身份验证、消息安全和多端同步安全。
鉴权体系采用 **TokenJWT 或自定义) + HTTPS/WebSocket** 方式。
------
## 2. 鉴权方式选择
| 方法 |
| -------------------------------------- |
| JWTJSON Web Token+ Redis黑名单机制 |
------
## 3. Token 生成规则
### 3.1 Token 内容结构JWT 示例)
```
{
"userId": 1001, // 用户ID
"iat": 1700000000, // 签发时间Unix时间戳
"exp": 1700003600, // 过期时间
"deviceId": "uuid-xxxx", // 设备ID用于多端区分
"role": "user" // 角色
}
```
- **签名算法**HMAC-SHA256 或 RSA
- **签名秘钥**:服务端统一管理,不暴露给客户端
------
### 3.2 Token 生成流程
1. 用户登录(用户名/密码)
2. 验证用户名与密码正确
3. 生成 Token写入 Redis可选
4. 返回 Token 给客户端
**响应示例**
```
{
"code": 0,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
```
------
## 4. Token 使用
### 4.1 HTTP 接口鉴权
- 客户端请求带上 Header
```
Authorization: Bearer <token>
```
- 后端解析 Token
1. 校验签名
2. 校验 exp 是否过期
3. 校验 Redis 黑名单(可选)
- 不通过返回 401 / code 1006
------
### 4.2 WebSocket 鉴权
- 建立连接时通过 Query 或 Header 传 Token
```
ws://example.com/ws?token=xxxx&deviceId=uuid-001
```
- 握手阶段:
1. 服务器验证 Token
2. 成功返回 AUTH_SUCCESS
3. 失败返回 AUTH_FAIL 并关闭连接
------
## 5. Token 过期策略
| 类型 | 建议值 | 说明 |
| ------------------ | ---------------------- | ---------------------------------------- |
| 短期 Token | 30 分钟 ~ 1 小时 | 防止长时间泄露 |
| 长期 Refresh Token | 7 ~ 30 天 | 用于获取新 Token安全性高 |
| WebSocket 长连接 | Token 与短期有效期一致 | 客户端定期刷新 Token心跳或重连时验证 |
### 5.1 Token 刷新流程
1. 客户端 Token 快过期时,调用刷新接口
2. 服务端验证 Refresh Token
3. 返回新 Token更新 Redis / 黑名单
------
## 6. 多端登录处理
- **每个设备对应一个 deviceId**
- Token 中绑定 deviceId
- 多端策略:
1. **允许多端同时登录**:每端单独维护 Token
2. **限制单端登录**:新登录覆盖旧设备 Token
3. **设备列表管理**:可查看在线设备并强制下线

View File

@ -1,401 +1,401 @@
# 接口文档REST API — 聊天系统
> 统一响应格式JSON
```
{
"code": 0,
"message": "请求成功",
"data": {}
}
```
- `code`:参照响应 Code 规范0 成功,非 0 为错误)。
- `message`:提示文本。
- `data`:返回主体。
------
## 通用约定
- 所有需要登录的接口必须在 Header 中带 `Authorization: Bearer <token>`
- 时间戳统一使用 Unix 秒。
- 分页统一采用 `page`第几页从1开始`limit`(每页大小)或基于时间/消息ID的 `afterMessageId` / `beforeTimestamp`
- 幂等性:对于可能重试的写操作,请求体中带 `requestId`
- Content-Type: `application/json`(文件上传除外)。
- 返回错误码请参考前面的响应 Code 文档。
------
## 目录
1. 鉴权Auth
2. 用户User
3. 好友Friend
4. 会话Conversation
5. 消息Message
6. 文件/上传File
7. 群组Group
8. 通知Notification
9. 管理后台Admin
10. 常见错误与限流
------
## 1. 鉴权Auth
### 1.1 注册
- URL: `POST /api/v1/auth/register`
- 请求:
```
{
"username": "alice",
"password": "password123",
"phone": "13800000000",
"email":"admin@admin.com",
"nickname":"测试用户",
"avatar": "https://cdn.example.com/avatar/1001.png",
}
```
- 成功响应:
```
{
"code": 0,
"message": "注册成功",
"data": { "userId": 1001 }
}
```
### 1.2 登录(返回 Token
- URL: `POST /api/v1/auth/login`
- 请求:
```
{
"username": "alice",
"password": "password123",
"deviceId": "uuid-device-001"
}
```
- 成功响应:
```
{
"code": 0,
"message": "登录成功",
"data": {
"token": "eyJ....",
"expires_in": 3600,
"refreshToken": "rft-xxxx"
}
}
```
### 1.3 刷新 Token
- URL: `POST /api/v1/auth/refresh`
- 请求:
```
{ "refreshToken": "rft-xxxx", "deviceId": "uuid-device-001" }
```
- 响应同登录(返回新 token
------
## 2. 用户User
### 2.1 获取当前用户信息
- URL: `GET /api/v1/user/me`
- Header: `Authorization: Bearer <token>`
- 响应 data 示例:
```
{
"id": 1001,
"username": "alice",
"nickname": "Alice",
"avatar": "https://cdn.example.com/avatar/1001.png",
"status": 1
}
```
### 2.2 修改用户资料
- URL: `PUT /api/v1/user/profile`
- 请求:
```
{
"nickname": "小艾",
"olinestatus": "0",
"avatar": "https://..."
}
```
### 2.3 根据 id 查询用户(用于搜索/加好友)
- URL: `GET /api/v1/user/{userId}`
- 响应含基本公开信息(不含敏感字段)。
------
## 3. 好友Friend
### 3.1 发送好友申请
- URL: `POST /api/v1/friend/request`
- 请求:
```
{
"toUserId": 1002,
"Description": "我们在项目中认识,申请加好友",
"requestId": "uuid-req-001" // 幂等字段
}
```
- 成功返回 `requestId` 或新记录 id。
### 3.2 列出好友申请(收/发)
- URL: `GET /api/v1/friend/requests?type=received|sent&page=1&limit=20`
### 3.3 处理好友申请(同意/拒绝)
- URL: `POST /api/v1/friend/request/{requestId}/handle`
- 请求:
```
{ "action": "accept" } // accept | reject
```
### 3.4 获取好友列表
- URL: `GET /api/v1/friend/list?page=1&limit=50`
- 返回好友数组id, nickname, avatar, remark
### 3.5 删除好友 / 拉黑
- URL: `DELETE /api/v1/friend/{friendId}`
- URL: `POST /api/v1/friend/{friendId}/block`
------
## 4. 会话Conversation
### 4.1 获取会话列表(聊天列表)
- URL: `GET /api/v1/conversations?page=1&limit=50`
- 返回每条会话示例:
```
{
"targetId": 1002,
"chatType": "single",
"lastMessage": { "messageId": 50001, "contentType":"text", "content":"你好", "timestamp": 1700000000 },
"unreadCount": 3,
"updatedAt": 1700000000
}
```
### 4.2 删除会话(清空会话/历史)
- URL: `DELETE /api/v1/conversation/{chatType}/{targetId}`
- 注chatType 为 `single``group`。删除会影响客户端显示/未读计数,历史消息视策略保留或软删除。
------
## 5. 消息Message
> 说明:即时消息优先通过 WebSocket 发送/接收REST 接口用于历史消息读取、离线发送备用、ACK、撤回等。
### 5.1 发送消息HTTP 版备用)
- URL: `POST /api/v1/message/send`
- 请求:
```
{
"requestId": "uuid-msg-001",
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
- 响应:
```
{ "code": 0, "data": { "messageId": 50001, "status": "sent" } }
```
- 注意:若用户在线,后端可同时通过 WebSocket 推送到接收端。
### 5.2 拉取历史消息分页或基于消息ID
- URL: `GET /api/v1/messages/history?chatType=single&targetId=1002&beforeMessageId=50000&limit=50`
- 返回消息数组(按时间倒序或正序,双方约定)。
### 5.3 同步未读/离线消息(登录/重连时)
- URL: `GET /api/v1/messages/sync?since=1700000000``afterMessageId=xxxxx`
- 返回:所有未读/未同步消息(或给定时间段内消息)。
### 5.4 消息已读/送达回执HTTP
- URL: `POST /api/v1/message/ack`
- 请求:
```
{
"messageId": 50001,
"status": "read", // delivered | read
"chatType": "single",
"from": 1002, // ack 发送者(接收方)
"to": 1001
}
```
### 5.5 撤回消息
- URL: `POST /api/v1/message/{messageId}/recall`
- 请求:
```
{ "requestId": "uuid-recall-001" }
```
- 响应成功后,服务器会向相关在线端推送 `MESSAGE_RECALL` 事件,更新 message.status。
### 5.6 删除单条消息(客户端侧删除/服务端删除)
- URL: `DELETE /api/v1/message/{messageId}`
- 注意区分“仅自己删除”与“全局删除(撤回)”。
------
## 6. 文件/上传File
### 6.1 上传文件(图片/语音/文档)
- URL: `POST /api/v1/file/upload`
- Content-Type: `multipart/form-data`
- 字段:`file`,可选 `type`、`attachedMessageRequestId`
- 成功响应:
```
{
"code": 0,
"data": {
"fileId": 9001,
"fileUrl": "https://oss.example.com/xxx.jpg",
"fileName": "xxx.jpg",
"fileSize": 12345
}
}
```
- 建议文件先上传到对象存储OSS/S3/MinIO返回 URL消息发送时引用该 URLmessage.content
### 6.2 下载文件
- 直接访问 `fileUrl` 或通过后端代理下载(带鉴权)。
------
## 7. 群组Group
### 7.1 创建群
- URL: `POST /api/v1/group/create`
- 请求:
```
{
"name": "项目群",
"ownerId": 1001,
"memberIds": [1002,1003],
"maxMembers": 500,
"needApproval": true // 加群是否需要审批
}
```
- 响应返回 `groupId`
### 7.2 获取群信息
- URL: `GET /api/v1/group/{groupId}`
### 7.3 邀请入群
- URL: `POST /api/v1/group/{groupId}/invite`
- 请求:
```
{ "inviter":1001, "invitees":[1004,1005], "message":"来加入我们吧" }
```
- 若群需要审批,发送 `group_join_request`;否则直接加入并更新 group_member。
### 7.4 加群申请(用户申请)
- URL: `POST /api/v1/group/{groupId}/join-request`
- 管理员/群主处理:`POST /api/v1/group/join-request/{requestId}/handle`
### 7.5 群成员管理(踢人/设管理员/退出群)
- 踢人:`POST /api/v1/group/{groupId}/kick`
- 退出:`POST /api/v1/group/{groupId}/leave`
- 设管理员:`POST /api/v1/group/{groupId}/role`
------
## 8. 通知Notification
### 8.1 获取通知列表
- URL: `GET /api/v1/notifications?page=1&limit=50`
- 类型包含:好友请求、群邀请、系统公告等。
### 8.2 标记通知为已读
- URL: `POST /api/v1/notification/{notificationId}/read`
------
## 9. 管理后台Admin
> 仅管理员或具备权限的账号访问(需在 token 中包含角色或额外权限校验)
### 9.1 管理员登录(同 auth
- URL: `POST /api/v1/admin/login`
### 9.2 查询用户列表
- URL: `GET /api/v1/admin/users?page=1&limit=50&keyword=alice`
### 9.3 禁用/启用用户
- URL: `POST /api/v1/admin/user/{userId}/ban`
- 请求:
```
{ "action": "ban", "reason": "违规传播" } // action: ban | unban
```
### 9.4 查询操作日志
# 接口文档REST API — 聊天系统
> 统一响应格式JSON
```
{
"code": 0,
"message": "请求成功",
"data": {}
}
```
- `code`:参照响应 Code 规范0 成功,非 0 为错误)。
- `message`:提示文本。
- `data`:返回主体。
------
## 通用约定
- 所有需要登录的接口必须在 Header 中带 `Authorization: Bearer <token>`
- 时间戳统一使用 Unix 秒。
- 分页统一采用 `page`第几页从1开始`limit`(每页大小)或基于时间/消息ID的 `afterMessageId` / `beforeTimestamp`
- 幂等性:对于可能重试的写操作,请求体中带 `requestId`
- Content-Type: `application/json`(文件上传除外)。
- 返回错误码请参考前面的响应 Code 文档。
------
## 目录
1. 鉴权Auth
2. 用户User
3. 好友Friend
4. 会话Conversation
5. 消息Message
6. 文件/上传File
7. 群组Group
8. 通知Notification
9. 管理后台Admin
10. 常见错误与限流
------
## 1. 鉴权Auth
### 1.1 注册
- URL: `POST /api/v1/auth/register`
- 请求:
```
{
"username": "alice",
"password": "password123",
"phone": "13800000000",
"email":"admin@admin.com",
"nickname":"测试用户",
"avatar": "https://cdn.example.com/avatar/1001.png",
}
```
- 成功响应:
```
{
"code": 0,
"message": "注册成功",
"data": { "userId": 1001 }
}
```
### 1.2 登录(返回 Token
- URL: `POST /api/v1/auth/login`
- 请求:
```
{
"username": "alice",
"password": "password123",
"deviceId": "uuid-device-001"
}
```
- 成功响应:
```
{
"code": 0,
"message": "登录成功",
"data": {
"token": "eyJ....",
"expires_in": 3600,
"refreshToken": "rft-xxxx"
}
}
```
### 1.3 刷新 Token
- URL: `POST /api/v1/auth/refresh`
- 请求:
```
{ "refreshToken": "rft-xxxx", "deviceId": "uuid-device-001" }
```
- 响应同登录(返回新 token
------
## 2. 用户User
### 2.1 获取当前用户信息
- URL: `GET /api/v1/user/me`
- Header: `Authorization: Bearer <token>`
- 响应 data 示例:
```
{
"id": 1001,
"username": "alice",
"nickname": "Alice",
"avatar": "https://cdn.example.com/avatar/1001.png",
"status": 1
}
```
### 2.2 修改用户资料
- URL: `PUT /api/v1/user/profile`
- 请求:
```
{
"nickname": "小艾",
"olinestatus": "0",
"avatar": "https://..."
}
```
### 2.3 根据 id 查询用户(用于搜索/加好友)
- URL: `GET /api/v1/user/{userId}`
- 响应含基本公开信息(不含敏感字段)。
------
## 3. 好友Friend
### 3.1 发送好友申请
- URL: `POST /api/v1/friend/request`
- 请求:
```
{
"toUserId": 1002,
"Description": "我们在项目中认识,申请加好友",
"requestId": "uuid-req-001" // 幂等字段
}
```
- 成功返回 `requestId` 或新记录 id。
### 3.2 列出好友申请(收/发)
- URL: `GET /api/v1/friend/requests?type=received|sent&page=1&limit=20`
### 3.3 处理好友申请(同意/拒绝)
- URL: `POST /api/v1/friend/request/{requestId}/handle`
- 请求:
```
{ "action": "accept" } // accept | reject
```
### 3.4 获取好友列表
- URL: `GET /api/v1/friend/list?page=1&limit=50`
- 返回好友数组id, nickname, avatar, remark
### 3.5 删除好友 / 拉黑
- URL: `DELETE /api/v1/friend/{friendId}`
- URL: `POST /api/v1/friend/{friendId}/block`
------
## 4. 会话Conversation
### 4.1 获取会话列表(聊天列表)
- URL: `GET /api/v1/conversations?page=1&limit=50`
- 返回每条会话示例:
```
{
"targetId": 1002,
"chatType": "single",
"lastMessage": { "messageId": 50001, "contentType":"text", "content":"你好", "timestamp": 1700000000 },
"unreadCount": 3,
"updatedAt": 1700000000
}
```
### 4.2 删除会话(清空会话/历史)
- URL: `DELETE /api/v1/conversation/{chatType}/{targetId}`
- 注chatType 为 `single``group`。删除会影响客户端显示/未读计数,历史消息视策略保留或软删除。
------
## 5. 消息Message
> 说明:即时消息优先通过 WebSocket 发送/接收REST 接口用于历史消息读取、离线发送备用、ACK、撤回等。
### 5.1 发送消息HTTP 版备用)
- URL: `POST /api/v1/message/send`
- 请求:
```
{
"requestId": "uuid-msg-001",
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
- 响应:
```
{ "code": 0, "data": { "messageId": 50001, "status": "sent" } }
```
- 注意:若用户在线,后端可同时通过 WebSocket 推送到接收端。
### 5.2 拉取历史消息分页或基于消息ID
- URL: `GET /api/v1/messages/history?chatType=single&targetId=1002&beforeMessageId=50000&limit=50`
- 返回消息数组(按时间倒序或正序,双方约定)。
### 5.3 同步未读/离线消息(登录/重连时)
- URL: `GET /api/v1/messages/sync?since=1700000000``afterMessageId=xxxxx`
- 返回:所有未读/未同步消息(或给定时间段内消息)。
### 5.4 消息已读/送达回执HTTP
- URL: `POST /api/v1/message/ack`
- 请求:
```
{
"messageId": 50001,
"status": "read", // delivered | read
"chatType": "single",
"from": 1002, // ack 发送者(接收方)
"to": 1001
}
```
### 5.5 撤回消息
- URL: `POST /api/v1/message/{messageId}/recall`
- 请求:
```
{ "requestId": "uuid-recall-001" }
```
- 响应成功后,服务器会向相关在线端推送 `MESSAGE_RECALL` 事件,更新 message.status。
### 5.6 删除单条消息(客户端侧删除/服务端删除)
- URL: `DELETE /api/v1/message/{messageId}`
- 注意区分“仅自己删除”与“全局删除(撤回)”。
------
## 6. 文件/上传File
### 6.1 上传文件(图片/语音/文档)
- URL: `POST /api/v1/file/upload`
- Content-Type: `multipart/form-data`
- 字段:`file`,可选 `type`、`attachedMessageRequestId`
- 成功响应:
```
{
"code": 0,
"data": {
"fileId": 9001,
"fileUrl": "https://oss.example.com/xxx.jpg",
"fileName": "xxx.jpg",
"fileSize": 12345
}
}
```
- 建议文件先上传到对象存储OSS/S3/MinIO返回 URL消息发送时引用该 URLmessage.content
### 6.2 下载文件
- 直接访问 `fileUrl` 或通过后端代理下载(带鉴权)。
------
## 7. 群组Group
### 7.1 创建群
- URL: `POST /api/v1/group/create`
- 请求:
```
{
"name": "项目群",
"ownerId": 1001,
"memberIds": [1002,1003],
"maxMembers": 500,
"needApproval": true // 加群是否需要审批
}
```
- 响应返回 `groupId`
### 7.2 获取群信息
- URL: `GET /api/v1/group/{groupId}`
### 7.3 邀请入群
- URL: `POST /api/v1/group/{groupId}/invite`
- 请求:
```
{ "inviter":1001, "invitees":[1004,1005], "message":"来加入我们吧" }
```
- 若群需要审批,发送 `group_join_request`;否则直接加入并更新 group_member。
### 7.4 加群申请(用户申请)
- URL: `POST /api/v1/group/{groupId}/join-request`
- 管理员/群主处理:`POST /api/v1/group/join-request/{requestId}/handle`
### 7.5 群成员管理(踢人/设管理员/退出群)
- 踢人:`POST /api/v1/group/{groupId}/kick`
- 退出:`POST /api/v1/group/{groupId}/leave`
- 设管理员:`POST /api/v1/group/{groupId}/role`
------
## 8. 通知Notification
### 8.1 获取通知列表
- URL: `GET /api/v1/notifications?page=1&limit=50`
- 类型包含:好友请求、群邀请、系统公告等。
### 8.2 标记通知为已读
- URL: `POST /api/v1/notification/{notificationId}/read`
------
## 9. 管理后台Admin
> 仅管理员或具备权限的账号访问(需在 token 中包含角色或额外权限校验)
### 9.1 管理员登录(同 auth
- URL: `POST /api/v1/admin/login`
### 9.2 查询用户列表
- URL: `GET /api/v1/admin/users?page=1&limit=50&keyword=alice`
### 9.3 禁用/启用用户
- URL: `POST /api/v1/admin/user/{userId}/ban`
- 请求:
```
{ "action": "ban", "reason": "违规传播" } // action: ban | unban
```
### 9.4 查询操作日志
- URL: `GET /api/v1/admin/logs?page=1&limit=50`

View File

@ -1,220 +1,220 @@
# 数据字典
### 表名Users
#### 表说明:储存用户个人信息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | ----------- | -------- | -------- | ------- | --------- | ------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Username | VARCHAR(50) | 是 | / | / | 唯一 | 唯一用户名 | admin |
| Password | VARCHAR(50) | 是 | / | / | / | 用户密码 | 123456 |
| NickName | VARCHAR(50) | 是 | / | / | / | 用户昵称 | / |
| OlineStatus | TINYINT | 是 | 0 | / | / | 用户在线状态<br />0默认不在线<br />1在线 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 |
| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 |
| Status | TINYINT | 是 | 1 | / | / | 账户状态<br />(0未激活,1正常,2封禁) | 1 |
| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识<br />0账号正常<br />1账号已删除 | 0 |
### 表名Friends
#### 表说明:好友关系映射
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| -------- | -------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键Users.Id | 索引 | 用户ID | 1 |
| FriendId | INT | 是 | / | 外键Users.Id | 索引 | 用户2ID | 2 |
| Status | TINYINT | 是 | 0 | / | / | 当前好友关系状态<br />0待通过,1已添加,2已拒绝,3已拉黑 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 好友关系创建时间 | 2025/9/29 |
### 表名Groups
#### 表说明:群聊
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ---------------- | ------------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | ------------------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAT20 | 是 | / | / | / | 群聊名称 | 测试群聊1 |
| GroupMaster | INT | 是 | / | 外键Users.Id | 索引 | 群主 | 1 |
| Auhority | TINYINT | 是 | 0 | / | / | 群权限<br />0需管理员同意,1任意人可加群,2不允许任何人加入 | 0 |
| AllMembersBanned | TINYINT | 是 | 0 | / | / | 全员禁言0允许发言2全员禁言 | 0 |
| Status | TINYINT | 是 | 1 | / | / | 群聊状态<br />(1正常,2封禁) | 1 |
| Announcement | TEXT | 否 | null | / | / | 群公告 | 这是一条测试群公告 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 群聊创建时间 | 2025/9/29 |
### 表名GroupMember
#### 表说明:群成员
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | -------- | -------- | -------- | --------------- | --------- | -------------------------------------- | -------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户编号 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| Role | TINYINT | 是 | 0 | / | / | 成员角色0:普通成员,1:管理员,2:群主) | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 加入群聊时间 | 1970/1/1 |
### 表名GroupInvite
#### 表说明:群聊邀请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | -------- | -------- | -------- | --------------- | --------- | ------------------------------------------------ | -------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| InvitedUser | INT | 是 | / | 外键(Users.Id) | 索引 | 被邀请用户 | 1 |
| InviteUser | INT | 是 | / | 外键(Users.Id) | 索引 | 邀请用户 | 1 |
| State | TINYINT | 是 | 0 | / | / | 当前状态(0:待被邀请人同意<br />1:被邀请人已同意) | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | 1970/1/1 |
### 表名GroupRequest
#### 表说明:群聊入群申请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | -------- | -------- | --------------- | --------------- | --------- | --------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 申请人 | 1 |
| State | TINYINT | 是 | 0 | / | / | 申请状态0:待管理员同意,1:已拒绝,2已同意 | 1 |
| Description | TEXT | 是 | xxx申请加入群聊 | / | / | 入群附言 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Messages
#### 表说明:用户消息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | -------- | -------- | -------- | -------------- | --------- | ------------------------------------------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| ChatType | TINYINT | 是 | 0 | / | / | 聊天类型<br />0私聊,1群聊 | 0 |
| MsgType | TINYINT | 是 | 0 | / | / | 消息类型<br />(0:文本,1图片,2语音,3视频,4文件5语音聊天,6视频聊天) | 0 |
| Content | TEXT | 是 | / | / | / | 消息内容 | / |
| Sender | INT | 是 | / | 外键(Users.Id) | 索引 | 发送者 | / |
| Recipient | INT | 是 | / | / | / | 接收者私聊为用户ID群聊为群聊ID | / |
| State | TINYINT | 是 | 0 | / | / | 消息状态(0:已发送,1:已撤回) | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 发送时间 | 、 |
### 表名Files
#### 表说明:文件
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | ------------ | -------- | -------- | ------------------- | --------- | -------------------- | ----------------------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAR(50) | 是 | / | / | / | 文件名 | 测试文件.txt |
| URL | VARCHAR(100) | 是 | / | / | / | 文件储存URL | https://baidu.com/1.txt |
| Size | INT | 是 | / | / | / | 文件大小单位KB | 1024 |
| Type | VARCHAT(10) | 是 | / | / | / | 文件类型 | txt |
| MessageId | INT | 是 | / | 外键Messages.Id | 索引 | 关联消息ID | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | 2025/9/29 |
### 表名Notifications
#### 表说明:系统通知消息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | ------------ | -------- | -------- | -------------- | --------- | ------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 否 | / | 外键(Users.Id) | 索引 | 接收人(为空为全体通知) | 1 |
| NType | TINYINT | 是 | 0 | / | / | 通知类型(0文本) | 0 |
| Title | NVARCHAR(20) | 是 | / | / | / | 通知标题 | 1 |
| Content | TEXT | 是 | / | / | / | 通知内容 | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Conversations
#### 表说明:用户会话
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------- | -------- | -------- | ------ | ----------------- | --------- | ------------------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户 | 1 |
| TargetId | INT | 是 | / | / | / | 对方ID群聊为群聊ID单聊为单聊ID | 1 |
| MsgType | INT | 是 | / | / | / | 消息类型同Messages.MsgType | / |
| lastMessageId | INT | 是 | / | 外键(Messages.Id) | 索引 | 最后一条消息ID | 1 |
| unreadCount | INT | 是 | / | / | / | 未读消息数 | / |
### 表名FriendRequest
#### 表说明:好友申请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------ | -------- | -------- | ------------------- | ---------------- | --------- | ------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| RequestUser | INT | 是 | / | 外键(Users.Id) | 索引 | 申请人 | / |
| ResponseUser | INT | 是 | / | 外键Users.Id | 索引 | 被申请人 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 申请时间 | / |
| Description | TEXT | 否 | xxx申请添加你为好友 | / | / | 申请附言 | / |
| State | TINYINT | 是 | 0 | / | / | 申请状态0待通过,1:拒绝,2:同意,3拉黑 | / |
### 表名Devices
#### 表说明:用户设备
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | -------- | -------- | -------- | -------------- | --------- | ---------------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 设备所属用户 | / |
| DType | TINYINT | 是 | / | / | / | 设备类型(<br />0:Android,1:Ios,2:PC,3Pad,4:未知) | 0 |
| LastLogin | DATETIME | 是 | 1970/1/1 | / | / | 最后一次登录 | / |
### 表名Login_Log
#### 表说明:登录日志
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | -------- | -------- | -------- | -------------- | --------- | ---------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| DType | TINYINT | 是 | / | / | / | 设备类型通Devices/DType | / |
| Logined | DATETIME | 是 | 1970/1/1 | / | / | 登录时间 | / |
| UserId | INT | 是 | / | 外键(Users.Id) | / | 登录用户 | / |
| State | TINYINT | 是 | 0 | / | / | 登录状态(0:登陆成功,1:未验证,2:已被拒绝) | / |
### 表名Admins
#### 表说明:系统管理员
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| -------- | ----------- | -------- | -------- | ---------------- | --------- | ----------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Username | VARCHAR(50) | 是 | / | / | / | 用户名 | / |
| Password | VARCHAR(50) | 是 | / | / | / | 密码 | / |
| RoleId | INT | 是 | / | 外键Roles.Id | 索引 | 角色 | / |
| State | TINYINT | 是 | 0 | / | / | 状态0:正常2封禁 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
| Updated | DATETIME | 是 | 1970/1/1 | / | / | 更新时间 | / |
### 表名Roles
#### 表说明:角色
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | ----------- | -------- | -------- | ------- | --------- | -------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAR(20) | 是 | / | / | / | 角色名称 | / |
| Description | TEXT | 是 | 空字符串 | / | / | 角色描述 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Permissions
#### 表说明:权限
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | ----------- | -------- | ------ | ------- | --------- | ----------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| PType | INT | 是 | 0 | / | / | 权限类型(0:增,1:删,2:改,3:查) | / |
| Name | VARCHAR(50) | 是 | / | / | / | 权限名称 | / |
| Code | INT | 是 | / | / | / | 权限编码 | / |
| Created | DATETIME | 是 | / | / | / | 创建时间 | / |
### 表名PermissionARole
#### 表说明:权限角色关联
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------ | -------- | -------- | ------ | ---------------------- | --------- | -------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| RoleId | INT | 是 | / | 外键Roles.Id | 索引 | 角色 | / |
# 数据字典
### 表名Users
#### 表说明:储存用户个人信息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | ----------- | -------- | -------- | ------- | --------- | ------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Username | VARCHAR(50) | 是 | / | / | 唯一 | 唯一用户名 | admin |
| Password | VARCHAR(50) | 是 | / | / | / | 用户密码 | 123456 |
| NickName | VARCHAR(50) | 是 | / | / | / | 用户昵称 | / |
| OlineStatus | TINYINT | 是 | 0 | / | / | 用户在线状态<br />0默认不在线<br />1在线 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 |
| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 |
| Status | TINYINT | 是 | 1 | / | / | 账户状态<br />(0未激活,1正常,2封禁) | 1 |
| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识<br />0账号正常<br />1账号已删除 | 0 |
### 表名Friends
#### 表说明:好友关系映射
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| -------- | -------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键Users.Id | 索引 | 用户ID | 1 |
| FriendId | INT | 是 | / | 外键Users.Id | 索引 | 用户2ID | 2 |
| Status | TINYINT | 是 | 0 | / | / | 当前好友关系状态<br />0待通过,1已添加,2已拒绝,3已拉黑 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 好友关系创建时间 | 2025/9/29 |
### 表名Groups
#### 表说明:群聊
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ---------------- | ------------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | ------------------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAT20 | 是 | / | / | / | 群聊名称 | 测试群聊1 |
| GroupMaster | INT | 是 | / | 外键Users.Id | 索引 | 群主 | 1 |
| Auhority | TINYINT | 是 | 0 | / | / | 群权限<br />0需管理员同意,1任意人可加群,2不允许任何人加入 | 0 |
| AllMembersBanned | TINYINT | 是 | 0 | / | / | 全员禁言0允许发言2全员禁言 | 0 |
| Status | TINYINT | 是 | 1 | / | / | 群聊状态<br />(1正常,2封禁) | 1 |
| Announcement | TEXT | 否 | null | / | / | 群公告 | 这是一条测试群公告 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 群聊创建时间 | 2025/9/29 |
### 表名GroupMember
#### 表说明:群成员
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | -------- | -------- | -------- | --------------- | --------- | -------------------------------------- | -------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户编号 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| Role | TINYINT | 是 | 0 | / | / | 成员角色0:普通成员,1:管理员,2:群主) | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 加入群聊时间 | 1970/1/1 |
### 表名GroupInvite
#### 表说明:群聊邀请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | -------- | -------- | -------- | --------------- | --------- | ------------------------------------------------ | -------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| InvitedUser | INT | 是 | / | 外键(Users.Id) | 索引 | 被邀请用户 | 1 |
| InviteUser | INT | 是 | / | 外键(Users.Id) | 索引 | 邀请用户 | 1 |
| State | TINYINT | 是 | 0 | / | / | 当前状态(0:待被邀请人同意<br />1:被邀请人已同意) | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | 1970/1/1 |
### 表名GroupRequest
#### 表说明:群聊入群申请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | -------- | -------- | --------------- | --------------- | --------- | --------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| GroupId | INT | 是 | / | 外键(Groups.Id) | 索引 | 群聊编号 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 申请人 | 1 |
| State | TINYINT | 是 | 0 | / | / | 申请状态0:待管理员同意,1:已拒绝,2已同意 | 1 |
| Description | TEXT | 是 | xxx申请加入群聊 | / | / | 入群附言 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Messages
#### 表说明:用户消息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | -------- | -------- | -------- | -------------- | --------- | ------------------------------------------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| ChatType | TINYINT | 是 | 0 | / | / | 聊天类型<br />0私聊,1群聊 | 0 |
| MsgType | TINYINT | 是 | 0 | / | / | 消息类型<br />(0:文本,1图片,2语音,3视频,4文件5语音聊天,6视频聊天) | 0 |
| Content | TEXT | 是 | / | / | / | 消息内容 | / |
| Sender | INT | 是 | / | 外键(Users.Id) | 索引 | 发送者 | / |
| Recipient | INT | 是 | / | / | / | 接收者私聊为用户ID群聊为群聊ID | / |
| State | TINYINT | 是 | 0 | / | / | 消息状态(0:已发送,1:已撤回) | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 发送时间 | 、 |
### 表名Files
#### 表说明:文件
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | ------------ | -------- | -------- | ------------------- | --------- | -------------------- | ----------------------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAR(50) | 是 | / | / | / | 文件名 | 测试文件.txt |
| URL | VARCHAR(100) | 是 | / | / | / | 文件储存URL | https://baidu.com/1.txt |
| Size | INT | 是 | / | / | / | 文件大小单位KB | 1024 |
| Type | VARCHAT(10) | 是 | / | / | / | 文件类型 | txt |
| MessageId | INT | 是 | / | 外键Messages.Id | 索引 | 关联消息ID | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | 2025/9/29 |
### 表名Notifications
#### 表说明:系统通知消息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | ------------ | -------- | -------- | -------------- | --------- | ------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 否 | / | 外键(Users.Id) | 索引 | 接收人(为空为全体通知) | 1 |
| NType | TINYINT | 是 | 0 | / | / | 通知类型(0文本) | 0 |
| Title | NVARCHAR(20) | 是 | / | / | / | 通知标题 | 1 |
| Content | TEXT | 是 | / | / | / | 通知内容 | 1 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Conversations
#### 表说明:用户会话
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------- | -------- | -------- | ------ | ----------------- | --------- | ------------------------------------ | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户 | 1 |
| TargetId | INT | 是 | / | / | / | 对方ID群聊为群聊ID单聊为单聊ID | 1 |
| MsgType | INT | 是 | / | / | / | 消息类型同Messages.MsgType | / |
| lastMessageId | INT | 是 | / | 外键(Messages.Id) | 索引 | 最后一条消息ID | 1 |
| unreadCount | INT | 是 | / | / | / | 未读消息数 | / |
### 表名FriendRequest
#### 表说明:好友申请
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------ | -------- | -------- | ------------------- | ---------------- | --------- | ------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| RequestUser | INT | 是 | / | 外键(Users.Id) | 索引 | 申请人 | / |
| ResponseUser | INT | 是 | / | 外键Users.Id | 索引 | 被申请人 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 申请时间 | / |
| Description | TEXT | 否 | xxx申请添加你为好友 | / | / | 申请附言 | / |
| State | TINYINT | 是 | 0 | / | / | 申请状态0待通过,1:拒绝,2:同意,3拉黑 | / |
### 表名Devices
#### 表说明:用户设备
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| --------- | -------- | -------- | -------- | -------------- | --------- | ---------------------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 设备所属用户 | / |
| DType | TINYINT | 是 | / | / | / | 设备类型(<br />0:Android,1:Ios,2:PC,3Pad,4:未知) | 0 |
| LastLogin | DATETIME | 是 | 1970/1/1 | / | / | 最后一次登录 | / |
### 表名Login_Log
#### 表说明:登录日志
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | -------- | -------- | -------- | -------------- | --------- | ---------------------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| DType | TINYINT | 是 | / | / | / | 设备类型通Devices/DType | / |
| Logined | DATETIME | 是 | 1970/1/1 | / | / | 登录时间 | / |
| UserId | INT | 是 | / | 外键(Users.Id) | / | 登录用户 | / |
| State | TINYINT | 是 | 0 | / | / | 登录状态(0:登陆成功,1:未验证,2:已被拒绝) | / |
### 表名Admins
#### 表说明:系统管理员
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| -------- | ----------- | -------- | -------- | ---------------- | --------- | ----------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Username | VARCHAR(50) | 是 | / | / | / | 用户名 | / |
| Password | VARCHAR(50) | 是 | / | / | / | 密码 | / |
| RoleId | INT | 是 | / | 外键Roles.Id | 索引 | 角色 | / |
| State | TINYINT | 是 | 0 | / | / | 状态0:正常2封禁 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
| Updated | DATETIME | 是 | 1970/1/1 | / | / | 更新时间 | / |
### 表名Roles
#### 表说明:角色
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | ----------- | -------- | -------- | ------- | --------- | -------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Name | VARCHAR(20) | 是 | / | / | / | 角色名称 | / |
| Description | TEXT | 是 | 空字符串 | / | / | 角色描述 | / |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 创建时间 | / |
### 表名Permissions
#### 表说明:权限
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------- | ----------- | -------- | ------ | ------- | --------- | ----------------------------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| PType | INT | 是 | 0 | / | / | 权限类型(0:增,1:删,2:改,3:查) | / |
| Name | VARCHAR(50) | 是 | / | / | / | 权限名称 | / |
| Code | INT | 是 | / | / | / | 权限编码 | / |
| Created | DATETIME | 是 | / | / | / | 创建时间 | / |
### 表名PermissionARole
#### 表说明:权限角色关联
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ------------ | -------- | -------- | ------ | ---------------------- | --------- | -------- | ------ |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| RoleId | INT | 是 | / | 外键Roles.Id | 索引 | 角色 | / |
| PermissionId | INT | 是 | / | 外键Permissions.Id | 索引 | 权限 | / |

View File

@ -1,64 +1,64 @@
# 需求规格说明书SRS
## 1. 项目背景
- #### 项目目标:
本项目旨在实现一个类似 QQ 的即时通讯系统,提供用户注册、好友聊天、群聊、文件传输等核心功能。
- 使用场景:学习练手 + 内部小团队沟通工具。
- #### 项目范围:
学习项目
- #### 业务价值:
学习项目
## 2. 用户需求
- 普通用户:注册、登录、聊天、加好友
- 管理员:封禁违规账号、管理群聊
- 使用场景1v1 聊天、群聊、发送文件、发送表情/图片等
## 3. 功能需求
- ##### 3.1 账号系统
- F-1 用户注册:支持手机号/邮箱注册,需验证唯一性。
- F-2 用户登录:支持账号+密码、Token 鉴权。
- F-3 用户资料:可修改头像、昵称、个性签名。
##### 3.2 好友系统
- F-4 添加好友:通过账号/手机号搜索并申请。
- F-5 好友请求:系统通知对方,同意/拒绝。
- F-6 删除好友、拉黑。
##### 3.3 消息系统
- F-7 单聊:支持文本、表情、图片、文件。
- F-8 群聊:支持多人实时消息。
- F-9 消息状态:已发送、已送达、已读(暂时只在数据库层面标记已读,不显示在客户端)。
- F-10 消息管理:撤回、删除、搜索历史记录。
##### 3.4 群聊功能
- F-11 创建群聊:指定群名称,邀请成员。
- F-12 群管理:踢人、设管理员、发布公告。
- F-13 群人数上限:本期 500 人。
##### 3.5 系统通知
- F-14 好友申请通知。
- F-15 群邀请通知。
- F-16 新消息推送WebSocket
## 4. 非功能需求
- 实时性:消息延迟 ≤ 1 秒
- 并发性:单群支持 ≥ 500 人在线聊天
- 安全性消息加密传输WebSocket + TLS
- 可扩展性:后端支持水平扩展(分布式 IM 服务器) ***<u>此条暂不要求</u>***
## 5. 约束与假设
- 本期仅支持 Web 端PC + H5移动端后续开发
- 音视频通话仅提供基础功能,不做美颜、录屏
## 6.验收标准
- 两个用户能互加好友并聊天。
- 群聊消息在 500 人场景下稳定传递。
# 需求规格说明书SRS
## 1. 项目背景
- #### 项目目标:
本项目旨在实现一个类似 QQ 的即时通讯系统,提供用户注册、好友聊天、群聊、文件传输等核心功能。
- 使用场景:学习练手 + 内部小团队沟通工具。
- #### 项目范围:
学习项目
- #### 业务价值:
学习项目
## 2. 用户需求
- 普通用户:注册、登录、聊天、加好友
- 管理员:封禁违规账号、管理群聊
- 使用场景1v1 聊天、群聊、发送文件、发送表情/图片等
## 3. 功能需求
- ##### 3.1 账号系统
- F-1 用户注册:支持手机号/邮箱注册,需验证唯一性。
- F-2 用户登录:支持账号+密码、Token 鉴权。
- F-3 用户资料:可修改头像、昵称、个性签名。
##### 3.2 好友系统
- F-4 添加好友:通过账号/手机号搜索并申请。
- F-5 好友请求:系统通知对方,同意/拒绝。
- F-6 删除好友、拉黑。
##### 3.3 消息系统
- F-7 单聊:支持文本、表情、图片、文件。
- F-8 群聊:支持多人实时消息。
- F-9 消息状态:已发送、已送达、已读(暂时只在数据库层面标记已读,不显示在客户端)。
- F-10 消息管理:撤回、删除、搜索历史记录。
##### 3.4 群聊功能
- F-11 创建群聊:指定群名称,邀请成员。
- F-12 群管理:踢人、设管理员、发布公告。
- F-13 群人数上限:本期 500 人。
##### 3.5 系统通知
- F-14 好友申请通知。
- F-15 群邀请通知。
- F-16 新消息推送WebSocket
## 4. 非功能需求
- 实时性:消息延迟 ≤ 1 秒
- 并发性:单群支持 ≥ 500 人在线聊天
- 安全性消息加密传输WebSocket + TLS
- 可扩展性:后端支持水平扩展(分布式 IM 服务器) ***<u>此条暂不要求</u>***
## 5. 约束与假设
- 本期仅支持 Web 端PC + H5移动端后续开发
- 音视频通话仅提供基础功能,不做美颜、录屏
## 6.验收标准
- 两个用户能互加好友并聊天。
- 群聊消息在 500 人场景下稳定传递。
- 消息能在弱网环境下重试并成功送达。

View File

@ -1,285 +1,285 @@
# 📘 WebSocket 通讯协议设计文档
## 1. 概述
本协议用于实现 **即时聊天IM系统的实时消息传输**
客户端通过 WebSocket 连接后与服务器保持长连接,实现消息推送、状态同步、群聊与单聊。
**支持功能**
- 用户登录鉴权
- 单聊消息发送/接收
- 群聊消息发送/接收
- 消息撤回、已读回执
- 心跳保活与断线重连
- 系统通知(好友请求、群邀请)
------
## 2. 消息传输格式
### 2.1 基础消息结构JSON
```
{
"type": "MESSAGE_TYPE",
"requestId": "string", // 客户端生成的请求ID便于幂等
"from": 1001, // 发送者ID
"to": 1002, // 接收者ID单聊或群ID群聊
"chatType": "single", // "single" | "group"
"contentType": "text", // "text" | "image" | "file" | "voice" | "system"
"content": "消息内容或文件URL",
"timestamp": 1700000000 // Unix时间戳
}
```
------
### 2.2 常用 type 枚举
| type | 说明 |
| -------------- | ------------------------- |
| AUTH | 握手鉴权 |
| HEARTBEAT | 心跳保活 |
| MESSAGE | 普通聊天消息(单聊/群聊) |
| MESSAGE_ACK | 消息已读/送达回执 |
| MESSAGE_RECALL | 消息撤回 |
| FRIEND_REQUEST | 好友申请通知 |
| GROUP_INVITE | 群邀请通知 |
| SYSTEM_NOTICE | 系统公告/通知 |
| ERROR | 错误消息 |
------
## 3. 握手与鉴权
### 3.1 客户端连接
```
ws://example.com/ws?token=xxxx
```
- 客户端通过 Token 鉴权
- 服务器验证 Token 后,返回 AUTH_SUCCESS 或 AUTH_FAIL
### 3.2 服务端响应示例
**成功:**
```
{
"type": "AUTH",
"status": "success",
"userId": 1001,
"timestamp": 1700000000
}
```
**失败:**
```
{
"type": "AUTH",
"status": "fail",
"code": 1006,
"message": "Token无效或过期"
}
```
------
## 4. 心跳机制
### 4.1 客户端发送
```
{
"type": "HEARTBEAT",
"timestamp": 1700000000
}
```
### 4.2 服务器响应
```
{
"type": "HEARTBEAT",
"timestamp": 1700000000
}
```
- **客户端**:每隔 30 秒发送一次心跳
- **服务器**:若 2 倍心跳时间未收到消息,则断开连接
------
## 5. 消息传输
### 5.1 单聊消息
客户端发送:
```
{
"type": "MESSAGE",
"requestId": "uuid-001",
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
服务器推送给接收者:
```
{
"type": "MESSAGE",
"messageId": 50001,
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
------
### 5.2 群聊消息
```
{
"type": "MESSAGE",
"requestId": "uuid-002",
"from": 1001,
"to": 3001, // 群ID
"chatType": "group",
"contentType": "image",
"content": "http://img.example.com/xxx.jpg",
"timestamp": 1700000000
}
```
服务器会 **推送到群成员列表(除了自己)**
------
### 5.3 消息回执MESSAGE_ACK
客户端收到消息后发送:
```
{
"type": "MESSAGE_ACK",
"messageId": 50001,
"from": 1002,
"to": 1001,
"chatType": "single",
"status": "read",
"timestamp": 1700000000
}
```
服务器更新消息状态,并可推送给发送方。
------
### 5.4 消息撤回MESSAGE_RECALL
客户端请求撤回消息:
```
{
"type": "MESSAGE_RECALL",
"messageId": 50001,
"from": 1001,
"to": 1002,
"chatType": "single",
"timestamp": 1700000010
}
```
服务器验证是否允许撤回(时间限制、权限等),允许则推送给接收方:
```
{
"type": "MESSAGE_RECALL",
"messageId": 50001,
"from": 1001,
"chatType": "single",
"status": "success",
"timestamp": 1700000010
}
```
------
## 6. 好友 / 群邀请通知
### 6.1 好友申请FRIEND_REQUEST
```
{
"type": "FRIEND_REQUEST",
"requestId": "uuid-003",
"from": 1001,
"to": 1002,
"content": "加个好友吧",
"timestamp": 1700000020
}
```
### 6.2 群邀请GROUP_INVITE
```
{
"type": "GROUP_INVITE",
"inviteId": "uuid-004",
"groupId": 3001,
"inviter": 1001,
"invitee": 1003,
"content": "邀请你加入群聊",
"timestamp": 1700000030
}
```
------
## 7. 错误处理ERROR
```
{
"type": "ERROR",
"code": 2300,
"message": "消息发送失败",
"requestId": "uuid-001",
"timestamp": 1700000040
}
```
- **code** 对应响应 Code 规范
- **requestId** 可帮助客户端确认失败的具体请求
------
## 8. 断线重连
- 客户端断线后,尝试每隔 5 秒重连一次
- 重连成功后,重新发送 AUTH 消息进行鉴权
- 重连后可请求 **未读消息同步**message 表或 Redis 缓存)
------
## 9. 附录contentType 示例
| contentType | content 示例 | 描述 |
| ----------- | ---------------------------------- | ----------------- |
| text | "你好" | 文本消息 |
| image | "http://img.example.com/xxx.jpg" | 图片 URL |
| file | "http://file.example.com/xxx.pdf" | 文件 URL + 文件名 |
| voice | "http://audio.example.com/xxx.mp3" | 语音 URL + 时长 |
# 📘 WebSocket 通讯协议设计文档
## 1. 概述
本协议用于实现 **即时聊天IM系统的实时消息传输**
客户端通过 WebSocket 连接后与服务器保持长连接,实现消息推送、状态同步、群聊与单聊。
**支持功能**
- 用户登录鉴权
- 单聊消息发送/接收
- 群聊消息发送/接收
- 消息撤回、已读回执
- 心跳保活与断线重连
- 系统通知(好友请求、群邀请)
------
## 2. 消息传输格式
### 2.1 基础消息结构JSON
```
{
"type": "MESSAGE_TYPE",
"requestId": "string", // 客户端生成的请求ID便于幂等
"from": 1001, // 发送者ID
"to": 1002, // 接收者ID单聊或群ID群聊
"chatType": "single", // "single" | "group"
"contentType": "text", // "text" | "image" | "file" | "voice" | "system"
"content": "消息内容或文件URL",
"timestamp": 1700000000 // Unix时间戳
}
```
------
### 2.2 常用 type 枚举
| type | 说明 |
| -------------- | ------------------------- |
| AUTH | 握手鉴权 |
| HEARTBEAT | 心跳保活 |
| MESSAGE | 普通聊天消息(单聊/群聊) |
| MESSAGE_ACK | 消息已读/送达回执 |
| MESSAGE_RECALL | 消息撤回 |
| FRIEND_REQUEST | 好友申请通知 |
| GROUP_INVITE | 群邀请通知 |
| SYSTEM_NOTICE | 系统公告/通知 |
| ERROR | 错误消息 |
------
## 3. 握手与鉴权
### 3.1 客户端连接
```
ws://example.com/ws?token=xxxx
```
- 客户端通过 Token 鉴权
- 服务器验证 Token 后,返回 AUTH_SUCCESS 或 AUTH_FAIL
### 3.2 服务端响应示例
**成功:**
```
{
"type": "AUTH",
"status": "success",
"userId": 1001,
"timestamp": 1700000000
}
```
**失败:**
```
{
"type": "AUTH",
"status": "fail",
"code": 1006,
"message": "Token无效或过期"
}
```
------
## 4. 心跳机制
### 4.1 客户端发送
```
{
"type": "HEARTBEAT",
"timestamp": 1700000000
}
```
### 4.2 服务器响应
```
{
"type": "HEARTBEAT",
"timestamp": 1700000000
}
```
- **客户端**:每隔 30 秒发送一次心跳
- **服务器**:若 2 倍心跳时间未收到消息,则断开连接
------
## 5. 消息传输
### 5.1 单聊消息
客户端发送:
```
{
"type": "MESSAGE",
"requestId": "uuid-001",
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
服务器推送给接收者:
```
{
"type": "MESSAGE",
"messageId": 50001,
"from": 1001,
"to": 1002,
"chatType": "single",
"contentType": "text",
"content": "你好",
"timestamp": 1700000000
}
```
------
### 5.2 群聊消息
```
{
"type": "MESSAGE",
"requestId": "uuid-002",
"from": 1001,
"to": 3001, // 群ID
"chatType": "group",
"contentType": "image",
"content": "http://img.example.com/xxx.jpg",
"timestamp": 1700000000
}
```
服务器会 **推送到群成员列表(除了自己)**
------
### 5.3 消息回执MESSAGE_ACK
客户端收到消息后发送:
```
{
"type": "MESSAGE_ACK",
"messageId": 50001,
"from": 1002,
"to": 1001,
"chatType": "single",
"status": "read",
"timestamp": 1700000000
}
```
服务器更新消息状态,并可推送给发送方。
------
### 5.4 消息撤回MESSAGE_RECALL
客户端请求撤回消息:
```
{
"type": "MESSAGE_RECALL",
"messageId": 50001,
"from": 1001,
"to": 1002,
"chatType": "single",
"timestamp": 1700000010
}
```
服务器验证是否允许撤回(时间限制、权限等),允许则推送给接收方:
```
{
"type": "MESSAGE_RECALL",
"messageId": 50001,
"from": 1001,
"chatType": "single",
"status": "success",
"timestamp": 1700000010
}
```
------
## 6. 好友 / 群邀请通知
### 6.1 好友申请FRIEND_REQUEST
```
{
"type": "FRIEND_REQUEST",
"requestId": "uuid-003",
"from": 1001,
"to": 1002,
"content": "加个好友吧",
"timestamp": 1700000020
}
```
### 6.2 群邀请GROUP_INVITE
```
{
"type": "GROUP_INVITE",
"inviteId": "uuid-004",
"groupId": 3001,
"inviter": 1001,
"invitee": 1003,
"content": "邀请你加入群聊",
"timestamp": 1700000030
}
```
------
## 7. 错误处理ERROR
```
{
"type": "ERROR",
"code": 2300,
"message": "消息发送失败",
"requestId": "uuid-001",
"timestamp": 1700000040
}
```
- **code** 对应响应 Code 规范
- **requestId** 可帮助客户端确认失败的具体请求
------
## 8. 断线重连
- 客户端断线后,尝试每隔 5 秒重连一次
- 重连成功后,重新发送 AUTH 消息进行鉴权
- 重连后可请求 **未读消息同步**message 表或 Redis 缓存)
------
## 9. 附录contentType 示例
| contentType | content 示例 | 描述 |
| ----------- | ---------------------------------- | ----------------- |
| text | "你好" | 文本消息 |
| image | "http://img.example.com/xxx.jpg" | 图片 URL |
| file | "http://file.example.com/xxx.pdf" | 文件 URL + 文件名 |
| voice | "http://audio.example.com/xxx.mp3" | 语音 URL + 时长 |
| system | "用户xxx加入群" | 系统消息 |

View File

@ -0,0 +1,8 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
max_line_length = 100

1
frontend/web/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

30
frontend/web/.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

View File

@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
}

9
frontend/web/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"recommendations": [
"Vue.volar",
"vitest.explorer",
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode"
]
}

50
frontend/web/README.md Normal file
View File

@ -0,0 +1,50 @@
# web
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Recommended Browser Setup
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
- Firefox:
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Compile and Minify for Production
```sh
npm run build
```
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
npm run test:unit
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```

View File

@ -0,0 +1,32 @@
import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
import pluginVitest from '@vitest/eslint-plugin'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
export default defineConfig([
{
name: 'app/files-to-lint',
files: ['**/*.{js,mjs,jsx,vue}'],
},
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
{
languageOptions: {
globals: {
...globals.browser,
},
},
},
js.configs.recommended,
...pluginVue.configs['flat/essential'],
{
...pluginVitest.configs.recommended,
files: ['src/**/__tests__/*'],
},
skipFormatting,
])

13
frontend/web/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@ -0,0 +1,8 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

6334
frontend/web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

37
frontend/web/package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "web",
"version": "0.0.0",
"private": true,
"type": "module",
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test:unit": "vitest",
"lint": "eslint . --fix",
"format": "prettier --write src/"
},
"dependencies": {
"pinia": "^3.0.3",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@vitejs/plugin-vue": "^6.0.1",
"@vitest/eslint-plugin": "^1.3.13",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/test-utils": "^2.4.6",
"eslint": "^9.33.0",
"eslint-plugin-vue": "~10.4.0",
"globals": "^16.3.0",
"jsdom": "^27.0.0",
"prettier": "3.6.2",
"vite": "^7.1.7",
"vite-plugin-vue-devtools": "^8.0.2",
"vitest": "^3.2.4"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

11
frontend/web/src/App.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup></script>
<template>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
</template>
<style scoped></style>

View File

@ -0,0 +1,11 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import App from '../App.vue'
describe('App', () => {
it('mounts renders properly', () => {
const wrapper = mount(App)
expect(wrapper.text()).toContain('You did it!')
})
})

12
frontend/web/src/main.js Normal file
View File

@ -0,0 +1,12 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

View File

@ -0,0 +1,8 @@
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [],
})
export default router

View File

@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

View File

@ -0,0 +1,18 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})

View File

@ -0,0 +1,14 @@
import { fileURLToPath } from 'node:url'
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: 'jsdom',
exclude: [...configDefaults.exclude, 'e2e/**'],
root: fileURLToPath(new URL('./', import.meta.url)),
},
}),
)