diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..3dbbcf3
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/bin
+**/charts
+**/docker-compose*
+**/compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
diff --git a/.env b/.env
new file mode 100644
index 0000000..ffcde48
--- /dev/null
+++ b/.env
@@ -0,0 +1,5 @@
+POSTGRES_DB="dombudg"
+POSTGRES_USER="postgres"
+POSTGRES_PASSWORD="postgres"
+
+CONNECTION_STRING="Host=database:5432;Database=${POSTGRES_DB};Username=${POSTGRES_USER};Password=${POSTGRES_PASSWORD};"
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..6e3c048
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,39 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/back/Controllers/bin/Debug/net8.0/Controllers.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/back/Controllers",
+ "stopAtEntry": false,
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ },
+ {
+ "name": "Docker .NET Launch",
+ "type": "docker",
+ "request": "launch",
+ "preLaunchTask": "docker-run: debug",
+ "netCore": {
+ "appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..ac38365
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,101 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/back/Api.sln",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary;ForceNoAlign"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/back/Api.sln",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary;ForceNoAlign"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/back/Api.sln"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "type": "docker-build",
+ "label": "docker-build: debug",
+ "dependsOn": [
+ "build"
+ ],
+ "dockerBuild": {
+ "tag": "dombudg:dev",
+ "target": "base",
+ "dockerfile": "${workspaceFolder}/back/Controllers/Dockerfile",
+ "context": "${workspaceFolder}",
+ "pull": true
+ },
+ "netCore": {
+ "appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
+ }
+ },
+ {
+ "type": "docker-build",
+ "label": "docker-build: release",
+ "dependsOn": [
+ "build"
+ ],
+ "dockerBuild": {
+ "tag": "dombudg:latest",
+ "dockerfile": "${workspaceFolder}/back/Controllers/Dockerfile",
+ "context": "${workspaceFolder}",
+ "platform": {
+ "os": "linux",
+ "architecture": "amd64"
+ },
+ "pull": true
+ },
+ "netCore": {
+ "appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
+ }
+ },
+ {
+ "type": "docker-run",
+ "label": "docker-run: debug",
+ "dependsOn": [
+ "docker-build: debug"
+ ],
+ "dockerRun": {},
+ "netCore": {
+ "appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj",
+ "enableDebugging": true
+ }
+ },
+ {
+ "type": "docker-run",
+ "label": "docker-run: release",
+ "dependsOn": [
+ "docker-build: release"
+ ],
+ "dockerRun": {},
+ "netCore": {
+ "appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/back/.gitignore b/back/.gitignore
new file mode 100644
index 0000000..104b544
--- /dev/null
+++ b/back/.gitignore
@@ -0,0 +1,484 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from `dotnet new gitignore`
+
+# dotenv files
+.env
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# Tye
+.tye/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
+.idea
+
+##
+## Visual studio for Mac
+##
+
+
+# globs
+Makefile.in
+*.userprefs
+*.usertasks
+config.make
+config.status
+aclocal.m4
+install-sh
+autom4te.cache/
+*.tar.gz
+tarballs/
+test-results/
+
+# Mac bundle stuff
+*.dmg
+*.app
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# Vim temporary swap files
+*.swp
diff --git a/back/Api.sln b/back/Api.sln
new file mode 100644
index 0000000..c0cdbbb
--- /dev/null
+++ b/back/Api.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Controllers", "Controllers\Controllers.csproj", "{BEA05282-6DE5-4D67-983A-EF13AAF8EECE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{B937E273-1D6E-42DF-BD34-14DA5E71FC71}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "Contracts\Contracts.csproj", "{B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{A35121D4-7D41-4266-8DA4-87135E8ABF89}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/back/Contracts/Contracts.csproj b/back/Contracts/Contracts.csproj
new file mode 100644
index 0000000..fa71b7a
--- /dev/null
+++ b/back/Contracts/Contracts.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs
new file mode 100644
index 0000000..30f8dbd
--- /dev/null
+++ b/back/Contracts/DTOs/ChangeRecordDto.cs
@@ -0,0 +1,11 @@
+namespace Contracts.DTO;
+
+public class ChangeRecordDto
+{
+ public Guid Id { get; set; }
+ public Guid UserId { get; set; }
+ public Guid? SpendingGroupId { get; set; }
+ public string? SpendingGroupName { get; set; }
+ public decimal Sum { get; set; }
+ public DateTime ChangedAt { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/DTOs/SpendingGroupDto.cs b/back/Contracts/DTOs/SpendingGroupDto.cs
new file mode 100644
index 0000000..dd001fd
--- /dev/null
+++ b/back/Contracts/DTOs/SpendingGroupDto.cs
@@ -0,0 +1,10 @@
+namespace Contracts.DTO;
+
+public class SpendingGroupDto
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public Guid UserId { get; set; }
+ public List ChangeRecords { get; set; } = new();
+ public List SpendingPlans { get; set; } = new();
+}
\ No newline at end of file
diff --git a/back/Contracts/DTOs/SpendingPlanDto.cs b/back/Contracts/DTOs/SpendingPlanDto.cs
new file mode 100644
index 0000000..fc88578
--- /dev/null
+++ b/back/Contracts/DTOs/SpendingPlanDto.cs
@@ -0,0 +1,10 @@
+namespace Contracts.DTO;
+
+public class SpendingPlanDto
+{
+ public Guid Id { get; set; }
+ public Guid SpendingGroupId { get; set; }
+ public decimal Sum { get; set; }
+ public DateTime StartAt { get; set; }
+ public DateTime EndAt { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/DTOs/UserDTO.cs b/back/Contracts/DTOs/UserDTO.cs
new file mode 100644
index 0000000..e312313
--- /dev/null
+++ b/back/Contracts/DTOs/UserDTO.cs
@@ -0,0 +1,9 @@
+namespace Contracts.DTO;
+
+public class UserDto
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string Password { get; set; } = string.Empty;
+ public decimal Balance { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/DTOs/UserLoginDTO.cs b/back/Contracts/DTOs/UserLoginDTO.cs
new file mode 100644
index 0000000..31acccc
--- /dev/null
+++ b/back/Contracts/DTOs/UserLoginDTO.cs
@@ -0,0 +1,7 @@
+namespace Contracts.DTO;
+
+public class UserLoginDto
+{
+ public string Name { get; set; } = string.Empty;
+ public string Password { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/back/Contracts/Mappers/ChangeRecordMapper.cs b/back/Contracts/Mappers/ChangeRecordMapper.cs
new file mode 100644
index 0000000..8483bf2
--- /dev/null
+++ b/back/Contracts/Mappers/ChangeRecordMapper.cs
@@ -0,0 +1,16 @@
+using Contracts.DTO;
+using Contracts.ViewModels;
+
+namespace Contracts.Mappers;
+
+public static class ChangeRecordMapper
+{
+ public static ChangeRecordViewModel ToView(this ChangeRecordDto dto)
+ => new()
+ {
+ Id = dto.Id,
+ Sum = dto.Sum,
+ ChangedAt = dto.ChangedAt.ToString("dd.MM.yyyy"),
+ SpendingGroupName = dto.SpendingGroupName ?? string.Empty
+ };
+}
\ No newline at end of file
diff --git a/back/Contracts/Mappers/SpendingGroupMapper.cs b/back/Contracts/Mappers/SpendingGroupMapper.cs
new file mode 100644
index 0000000..fd6a987
--- /dev/null
+++ b/back/Contracts/Mappers/SpendingGroupMapper.cs
@@ -0,0 +1,16 @@
+using Contracts.DTO;
+using Contracts.ViewModels;
+
+namespace Contracts.Mappers;
+
+public static class SpendingGroupMapper
+{
+ public static SpendingGroupViewModel ToView(this SpendingGroupDto dto)
+ => new()
+ {
+ Id = dto.Id,
+ Name = dto.Name,
+ ChangeRecords = dto.ChangeRecords.Select(x => x.ToView()).ToList(),
+ SpendingPlans = dto.SpendingPlans.Select(x => x.ToView()).ToList()
+ };
+}
\ No newline at end of file
diff --git a/back/Contracts/Mappers/SpendingPlanMapper.cs b/back/Contracts/Mappers/SpendingPlanMapper.cs
new file mode 100644
index 0000000..1a2674e
--- /dev/null
+++ b/back/Contracts/Mappers/SpendingPlanMapper.cs
@@ -0,0 +1,16 @@
+using Contracts.DTO;
+using Contracts.ViewModels;
+
+namespace Contracts.Mappers;
+
+public static class SpendingPlanMapper
+{
+ public static SpendingPlanViewModel ToView(this SpendingPlanDto dto)
+ => new()
+ {
+ Id = dto.Id,
+ StartAt = dto.StartAt.ToString("dd.MM.yyyy"),
+ EndAt = dto.EndAt.ToString("dd.MM.yyyy"),
+ Sum = dto.Sum
+ };
+}
\ No newline at end of file
diff --git a/back/Contracts/Mappers/UserMapper.cs b/back/Contracts/Mappers/UserMapper.cs
new file mode 100644
index 0000000..a32afed
--- /dev/null
+++ b/back/Contracts/Mappers/UserMapper.cs
@@ -0,0 +1,16 @@
+using Contracts.DTO;
+using Contracts.ViewModels;
+
+namespace Contracts.Mappers;
+
+public static class UserMapper
+{
+ public static UserViewModel ToView(this UserDto user)
+ => new()
+ {
+ Id = user.Id,
+ Name = user.Name,
+ Balance = user.Balance
+ };
+
+}
\ No newline at end of file
diff --git a/back/Contracts/Repositories/IChangeRecordRepo.cs b/back/Contracts/Repositories/IChangeRecordRepo.cs
new file mode 100644
index 0000000..d8e835e
--- /dev/null
+++ b/back/Contracts/Repositories/IChangeRecordRepo.cs
@@ -0,0 +1,13 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+
+namespace Contracts.Repositories;
+
+public interface IChangeRecordRepo
+{
+ Task Create(ChangeRecordDto changeRecord);
+ Task Get(ChangeRecordSearch search);
+ Task> GetList(ChangeRecordSearch? search = null);
+ Task Update(ChangeRecordDto changeRecord);
+ Task Delete(ChangeRecordSearch search);
+}
\ No newline at end of file
diff --git a/back/Contracts/Repositories/ISpendingGroupRepo.cs b/back/Contracts/Repositories/ISpendingGroupRepo.cs
new file mode 100644
index 0000000..f8f7999
--- /dev/null
+++ b/back/Contracts/Repositories/ISpendingGroupRepo.cs
@@ -0,0 +1,13 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+
+namespace Contracts.Repositories;
+
+public interface ISpendingGroupRepo
+{
+ Task Get(SpendingGroupSearch search);
+ Task> GetList(SpendingGroupSearch? search = null);
+ Task Create(SpendingGroupDto spendingGroup);
+ Task Delete(SpendingGroupSearch search);
+ Task Update(SpendingGroupDto spendingGroup);
+}
diff --git a/back/Contracts/Repositories/ISpendingPlanRepo.cs b/back/Contracts/Repositories/ISpendingPlanRepo.cs
new file mode 100644
index 0000000..8dcfd4b
--- /dev/null
+++ b/back/Contracts/Repositories/ISpendingPlanRepo.cs
@@ -0,0 +1,13 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+
+namespace Contracts.Repositories;
+
+public interface ISpendingPlanRepo
+{
+ Task Create(SpendingPlanDto dto);
+ Task Update(SpendingPlanDto dto);
+ Task Delete(SpendingPlanSearch search);
+ Task Get(SpendingPlanSearch search);
+ Task> GetList(SpendingPlanSearch? search = null);
+}
\ No newline at end of file
diff --git a/back/Contracts/Repositories/IUserRepo.cs b/back/Contracts/Repositories/IUserRepo.cs
new file mode 100644
index 0000000..dab5cd0
--- /dev/null
+++ b/back/Contracts/Repositories/IUserRepo.cs
@@ -0,0 +1,13 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+
+namespace Contracts.Repositories;
+
+public interface IUserRepo
+{
+ public Task Get(UserSearch search);
+ public Task Create(UserDto user);
+ public Task Update(UserDto user);
+ public Task ChangeBalance(UserSearch search, decimal amount);
+ public Task Delete(UserSearch search);
+}
\ No newline at end of file
diff --git a/back/Contracts/SearchModels/ChangeRecordSearch.cs b/back/Contracts/SearchModels/ChangeRecordSearch.cs
new file mode 100644
index 0000000..cfad78f
--- /dev/null
+++ b/back/Contracts/SearchModels/ChangeRecordSearch.cs
@@ -0,0 +1,10 @@
+namespace Contracts.SearchModels;
+
+public class ChangeRecordSearch
+{
+ public Guid? Id { get; set; }
+ public Guid? SpendingGroupId { get; set; }
+ public DateTime? From { get; set; }
+ public DateTime? To { get; set; }
+ public Guid? UserId { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/SearchModels/SpendingGroupSearch.cs b/back/Contracts/SearchModels/SpendingGroupSearch.cs
new file mode 100644
index 0000000..8ae4ba6
--- /dev/null
+++ b/back/Contracts/SearchModels/SpendingGroupSearch.cs
@@ -0,0 +1,8 @@
+namespace Contracts.SearchModels;
+
+public class SpendingGroupSearch
+{
+ public Guid? Id { get; set; }
+ public string? Name { get; set; }
+ public Guid? UserId { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/SearchModels/SpendingPlanSearch.cs b/back/Contracts/SearchModels/SpendingPlanSearch.cs
new file mode 100644
index 0000000..0b53198
--- /dev/null
+++ b/back/Contracts/SearchModels/SpendingPlanSearch.cs
@@ -0,0 +1,6 @@
+namespace Contracts.SearchModels;
+
+public class SpendingPlanSearch
+{
+ public Guid? Id { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/SearchModels/UserSearch.cs b/back/Contracts/SearchModels/UserSearch.cs
new file mode 100644
index 0000000..7ea4178
--- /dev/null
+++ b/back/Contracts/SearchModels/UserSearch.cs
@@ -0,0 +1,7 @@
+namespace Contracts.SearchModels;
+
+public class UserSearch
+{
+ public Guid? Id { get; set; }
+ public string? Name { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/Services/IAuthService.cs b/back/Contracts/Services/IAuthService.cs
new file mode 100644
index 0000000..5829bce
--- /dev/null
+++ b/back/Contracts/Services/IAuthService.cs
@@ -0,0 +1,11 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+
+namespace Contracts.Services;
+
+public interface IAuthService
+{
+ public Task Login(UserLoginDto loginData);
+ public Task Register(UserDto user);
+}
\ No newline at end of file
diff --git a/back/Contracts/Services/IChangeRecordService.cs b/back/Contracts/Services/IChangeRecordService.cs
new file mode 100644
index 0000000..b9939e0
--- /dev/null
+++ b/back/Contracts/Services/IChangeRecordService.cs
@@ -0,0 +1,13 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+
+namespace Contracts.Services;
+
+public interface IChangeRecordService
+{
+ Task Create(ChangeRecordDto model);
+ Task Update(ChangeRecordDto model);
+ Task Delete(ChangeRecordSearch search);
+ Task> GetList(ChangeRecordSearch? search = null);
+}
\ No newline at end of file
diff --git a/back/Contracts/Services/ISpendingGroupService.cs b/back/Contracts/Services/ISpendingGroupService.cs
new file mode 100644
index 0000000..938806f
--- /dev/null
+++ b/back/Contracts/Services/ISpendingGroupService.cs
@@ -0,0 +1,14 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+
+namespace Contracts.Services;
+
+public interface ISpendingGroupService
+{
+ Task GetDetails(SpendingGroupSearch search);
+ Task> GetList(SpendingGroupSearch? search = null);
+ Task Create(SpendingGroupDto model);
+ Task Update(SpendingGroupDto model);
+ Task Delete(SpendingGroupSearch search);
+}
\ No newline at end of file
diff --git a/back/Contracts/Services/ISpendingPlanService.cs b/back/Contracts/Services/ISpendingPlanService.cs
new file mode 100644
index 0000000..086ec5b
--- /dev/null
+++ b/back/Contracts/Services/ISpendingPlanService.cs
@@ -0,0 +1,14 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+
+namespace Contracts.Services;
+
+public interface ISpendingPlanService
+{
+ Task GetDetails(SpendingPlanSearch search);
+ Task> GetList(SpendingPlanSearch? search = null);
+ Task Create(SpendingPlanDto spendingPlan);
+ Task Delete(SpendingPlanSearch search);
+ Task Update(SpendingPlanDto spendingPlan);
+}
\ No newline at end of file
diff --git a/back/Contracts/Services/IUserService.cs b/back/Contracts/Services/IUserService.cs
new file mode 100644
index 0000000..736d3bf
--- /dev/null
+++ b/back/Contracts/Services/IUserService.cs
@@ -0,0 +1,12 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+
+namespace Contracts.Services;
+
+public interface IUserService
+{
+ public Task GetDetails(UserSearch search);
+ public Task UpdateUserData(UserDto user);
+ public Task Delete(UserSearch search);
+}
\ No newline at end of file
diff --git a/back/Contracts/ViewModels/ChangeRecordViewModel.cs b/back/Contracts/ViewModels/ChangeRecordViewModel.cs
new file mode 100644
index 0000000..2140b32
--- /dev/null
+++ b/back/Contracts/ViewModels/ChangeRecordViewModel.cs
@@ -0,0 +1,9 @@
+namespace Contracts.ViewModels;
+
+public class ChangeRecordViewModel
+{
+ public Guid Id { get; set; }
+ public decimal Sum { get; set; }
+ public string ChangedAt { get; set; } = null!;
+ public string SpendingGroupName { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/back/Contracts/ViewModels/SpendingGroupViewModel.cs b/back/Contracts/ViewModels/SpendingGroupViewModel.cs
new file mode 100644
index 0000000..1a94317
--- /dev/null
+++ b/back/Contracts/ViewModels/SpendingGroupViewModel.cs
@@ -0,0 +1,9 @@
+namespace Contracts.ViewModels;
+
+public class SpendingGroupViewModel
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public List ChangeRecords { get; set; } = new();
+ public List SpendingPlans { get; set; } = new();
+}
\ No newline at end of file
diff --git a/back/Contracts/ViewModels/SpendingPlanViewModel.cs b/back/Contracts/ViewModels/SpendingPlanViewModel.cs
new file mode 100644
index 0000000..a75357e
--- /dev/null
+++ b/back/Contracts/ViewModels/SpendingPlanViewModel.cs
@@ -0,0 +1,9 @@
+namespace Contracts.ViewModels;
+
+public class SpendingPlanViewModel
+{
+ public Guid Id { get; set; }
+ public string StartAt { get; set; } = null!;
+ public string EndAt { get; set; } = null!;
+ public decimal Sum { get; set; }
+}
\ No newline at end of file
diff --git a/back/Contracts/ViewModels/UserViewModel.cs b/back/Contracts/ViewModels/UserViewModel.cs
new file mode 100644
index 0000000..9bf54dc
--- /dev/null
+++ b/back/Contracts/ViewModels/UserViewModel.cs
@@ -0,0 +1,8 @@
+namespace Contracts.ViewModels;
+
+public class UserViewModel
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public decimal Balance { get; set; }
+}
\ No newline at end of file
diff --git a/back/Controllers/Controllers.csproj b/back/Controllers/Controllers.csproj
new file mode 100644
index 0000000..03a20aa
--- /dev/null
+++ b/back/Controllers/Controllers.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/Controllers/Controllers.http b/back/Controllers/Controllers.http
new file mode 100644
index 0000000..f5c450d
--- /dev/null
+++ b/back/Controllers/Controllers.http
@@ -0,0 +1,5 @@
+@Controllers_HostAddress = http://localhost:5125
+
+Accept: application/json
+
+###
diff --git a/back/Controllers/Controllers/AuthController.cs b/back/Controllers/Controllers/AuthController.cs
new file mode 100644
index 0000000..3a5c5d1
--- /dev/null
+++ b/back/Controllers/Controllers/AuthController.cs
@@ -0,0 +1,63 @@
+using Contracts.DTO;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Microsoft.AspNetCore.Mvc;
+using Services.Support.Exceptions;
+
+namespace Controllers.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class AuthController : ControllerBase
+{
+ private readonly IAuthService _authService;
+
+ public AuthController(IAuthService authService)
+ {
+ _authService = authService;
+ }
+
+ [HttpPost]
+ public async Task> Login([FromBody] UserLoginDto loginData)
+ {
+ try
+ {
+ var user = await _authService.Login(loginData);
+ return Ok(user);
+ }
+ catch (ArgumentException ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ catch (UserNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPost("register")]
+ public async Task> Register([FromBody] UserDto user)
+ {
+ try
+ {
+ var createdUser = await _authService.Register(user);
+ return CreatedAtAction(nameof(Login), new { name = createdUser.Name }, createdUser);
+ }
+ catch (ArgumentException ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ catch (AlreadyExistsException ex)
+ {
+ return Conflict(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Controllers/ChangeRecordController.cs b/back/Controllers/Controllers/ChangeRecordController.cs
new file mode 100644
index 0000000..c823a99
--- /dev/null
+++ b/back/Controllers/Controllers/ChangeRecordController.cs
@@ -0,0 +1,100 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Microsoft.AspNetCore.Mvc;
+using Services.Support.Exceptions;
+
+namespace Controllers.Controllers;
+
+[Route("api/[controller]")]
+[ApiController]
+public class ChangeRecordController : ControllerBase
+{
+ private readonly IChangeRecordService _changeRecordService;
+
+ public ChangeRecordController(IChangeRecordService changeRecordService)
+ {
+ _changeRecordService = changeRecordService;
+ }
+
+ [HttpPost]
+ public async Task> CreateChangeRecord(
+ [FromBody] ChangeRecordDto dto)
+ {
+ try
+ {
+ var record = await _changeRecordService.Create(dto);
+ return CreatedAtAction(nameof(GetChangeRecords), record);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet]
+ public async Task>> GetChangeRecords()
+ {
+ try
+ {
+ var records = await _changeRecordService.GetList();
+ return Ok(records);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet("filter")]
+ public async Task>> GetChangeRecords(
+ [FromQuery] ChangeRecordSearch search)
+ {
+ try
+ {
+ var records = await _changeRecordService.GetList(search);
+ return Ok(records);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPatch]
+ public async Task> UpdateChangeRecord([FromBody] ChangeRecordDto dto)
+ {
+ try
+ {
+ var record = await _changeRecordService.Update(dto);
+ return Ok(record);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpDelete]
+ public async Task DeleteChangeRecord([FromQuery] ChangeRecordSearch search)
+ {
+ try
+ {
+ var record = await _changeRecordService.Delete(search);
+ return Ok(record);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Controllers/SpendingGroupController.cs b/back/Controllers/Controllers/SpendingGroupController.cs
new file mode 100644
index 0000000..635c06a
--- /dev/null
+++ b/back/Controllers/Controllers/SpendingGroupController.cs
@@ -0,0 +1,126 @@
+namespace Controllers.Extensions;
+
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Microsoft.AspNetCore.Mvc;
+using Services.Support.Exceptions;
+
+[ApiController]
+[Route("api/[controller]")]
+public class SpendingGroupController : ControllerBase
+{
+ private readonly ISpendingGroupService _spendingGroupService;
+
+ public SpendingGroupController(ISpendingGroupService spendingGroupService)
+ {
+ _spendingGroupService = spendingGroupService;
+ }
+ [HttpGet("{id}")]
+ public async Task> GetSpendingGroup(
+ Guid id,
+ [FromQuery] SpendingGroupSearch search)
+ {
+ try
+ {
+ search ??= new();
+ search.Id = id;
+
+ var group = await _spendingGroupService.GetDetails(search);
+ return Ok(group);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet]
+ public async Task>> GetSpendingGroups()
+ {
+ try
+ {
+ var groups = await _spendingGroupService.GetList();
+ return Ok(groups);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet("filter")]
+ public async Task>> GetSpendingGroups(
+ [FromQuery] SpendingGroupSearch search)
+ {
+ try
+ {
+ var groups = await _spendingGroupService.GetList(search);
+ return Ok(groups);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPost]
+ public async Task> CreateSpendingGroup(
+ [FromBody] SpendingGroupDto dto)
+ {
+ try
+ {
+ var group = await _spendingGroupService.Create(dto);
+ return CreatedAtAction(nameof(GetSpendingGroup), new { id = group.Id }, group);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPatch]
+ public async Task> UpdateSpendingGroup([FromBody] SpendingGroupDto dto)
+ {
+ try
+ {
+ var group = await _spendingGroupService.Update(dto);
+ return Ok(group);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpDelete]
+ public async Task DeleteSpendingGroup([FromQuery] SpendingGroupSearch search)
+ {
+ try
+ {
+ var group = await _spendingGroupService.Delete(search);
+ return Ok(group);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Controllers/SpendingPlanController.cs b/back/Controllers/Controllers/SpendingPlanController.cs
new file mode 100644
index 0000000..5f457b1
--- /dev/null
+++ b/back/Controllers/Controllers/SpendingPlanController.cs
@@ -0,0 +1,128 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Microsoft.AspNetCore.Mvc;
+using Services.Support.Exceptions;
+
+namespace Controllers.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class SpendingPlanController : ControllerBase
+{
+ private readonly ISpendingPlanService _spendingPlanService;
+
+ public SpendingPlanController(ISpendingPlanService spendingPlanService)
+ {
+ _spendingPlanService = spendingPlanService;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetSpendingPlan(
+ Guid id,
+ [FromQuery] SpendingPlanSearch search)
+ {
+ try
+ {
+ search ??= new();
+ search.Id = id;
+
+ var plan = await _spendingPlanService.GetDetails(search);
+ return Ok(plan);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet]
+ public async Task>> GetSpendingPlans()
+ {
+ try
+ {
+ var plans = await _spendingPlanService.GetList();
+ return Ok(plans);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpGet("filter")]
+ public async Task>> GetSpendingPlans(
+ [FromQuery] SpendingPlanSearch search)
+ {
+ try
+ {
+ var plans = await _spendingPlanService.GetList(search);
+ return Ok(plans);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPost]
+ public async Task> CreateSpendingPlan(
+ [FromBody] SpendingPlanDto dto)
+ {
+ try
+ {
+ var plan = await _spendingPlanService.Create(dto);
+ return CreatedAtAction(nameof(GetSpendingPlan), new { id = plan.Id }, plan);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPatch]
+ public async Task> UpdateSpendingPlan(
+ [FromBody] SpendingPlanDto dto)
+ {
+ try
+ {
+ var plan = await _spendingPlanService.Update(dto);
+ return Ok(plan);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpDelete]
+ public async Task DeleteSpendingPlan([FromQuery] SpendingPlanSearch search)
+ {
+ try
+ {
+ var plan = await _spendingPlanService.Delete(search);
+ return Ok(plan);
+ }
+ catch (EntityNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Controllers/UserController.cs b/back/Controllers/Controllers/UserController.cs
new file mode 100644
index 0000000..c93c276
--- /dev/null
+++ b/back/Controllers/Controllers/UserController.cs
@@ -0,0 +1,73 @@
+using Contracts.DTO;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Microsoft.AspNetCore.Mvc;
+using Services.Support.Exceptions;
+
+namespace Controllers.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class UserController : ControllerBase
+{
+ private readonly IUserService _userService;
+
+ public UserController(IUserService userService)
+ {
+ _userService = userService;
+ }
+ [HttpGet]
+ public async Task> GetUser([FromQuery] UserSearch search)
+ {
+ try
+ {
+ var user = await _userService.GetDetails(search);
+ return Ok(user);
+ }
+ catch (UserNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpPatch]
+ public async Task> UpdateUser([FromBody] UserDto user)
+ {
+ try
+ {
+ var updatedUser = await _userService.UpdateUserData(user);
+ return Ok(updatedUser);
+ }
+ catch (UserNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+
+ [HttpDelete]
+ public async Task> DeleteUser([FromQuery] UserSearch search)
+ {
+ try
+ {
+ var deletedUser = await _userService.Delete(search);
+ return Ok(deletedUser);
+ }
+ catch (UserNotFoundException ex)
+ {
+ return NotFound(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, ex.Message);
+ }
+ }
+}
diff --git a/back/Controllers/Dockerfile b/back/Controllers/Dockerfile
new file mode 100644
index 0000000..29bf5f0
--- /dev/null
+++ b/back/Controllers/Dockerfile
@@ -0,0 +1,24 @@
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+WORKDIR /app
+EXPOSE 5125
+
+ENV ASPNETCORE_URLS=http://+:5125
+
+USER app
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG configuration=Release
+WORKDIR /src
+COPY ["back/Controllers/Controllers.csproj", "back/Controllers/"]
+RUN dotnet restore "back/Controllers/Controllers.csproj"
+COPY . .
+WORKDIR "/src/back/Controllers"
+RUN dotnet build "Controllers.csproj" -c $configuration -o /app/build
+
+FROM build AS publish
+ARG configuration=Release
+RUN dotnet publish "Controllers.csproj" -c $configuration -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Controllers.dll"]
diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs
new file mode 100644
index 0000000..7d6cc0a
--- /dev/null
+++ b/back/Controllers/Extensions/AddDomainServicesExt.cs
@@ -0,0 +1,19 @@
+using Contracts.Services;
+using Services.Domain;
+
+namespace Controllers.Extensions;
+
+public static class AddDomainServicesExtension
+{
+ public static void AddDomainServices(this IServiceCollection services)
+ {
+ services.AddTransient();
+ services.AddTransient();
+
+ services.AddTransient();
+
+ services.AddTransient();
+
+ services.AddTransient();
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs
new file mode 100644
index 0000000..5da333a
--- /dev/null
+++ b/back/Controllers/Extensions/AddReposExt.cs
@@ -0,0 +1,17 @@
+using Contracts.Repositories;
+using Contracts.Services;
+using Infrastructure.Repositories;
+using Services.Domain;
+
+namespace Controllers.Extensions;
+
+public static class AddReposExtension
+{
+ public static void AddRepos(this IServiceCollection services)
+ {
+ services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Extensions/DatabaseSetupExt.cs b/back/Controllers/Extensions/DatabaseSetupExt.cs
new file mode 100644
index 0000000..20592af
--- /dev/null
+++ b/back/Controllers/Extensions/DatabaseSetupExt.cs
@@ -0,0 +1,31 @@
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+
+namespace Controllers.Extensions;
+
+public static class DatabaseSetupExtension
+{
+ public static void AddDbConnectionService(this IServiceCollection services, IConfiguration config)
+ {
+ var connectionString = config.GetConnectionString("DefaultConnection")
+ ?? throw new ArgumentException("Нет строки подключения");
+ Console.WriteLine("Connection string: " + connectionString);
+ services.AddDbContext(options => options.UseNpgsql(connectionString));
+ services.AddSingleton, DbContextFactory>();
+ }
+
+ public static void MigrateDb(this IApplicationBuilder app)
+ {
+ try
+ {
+ using var scope = app.ApplicationServices.CreateScope();
+ var context = scope.ServiceProvider.GetRequiredService>();
+ using var db = context.CreateDbContext();
+ db.Database.Migrate();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Controllers/Program.cs b/back/Controllers/Program.cs
new file mode 100644
index 0000000..2c70319
--- /dev/null
+++ b/back/Controllers/Program.cs
@@ -0,0 +1,33 @@
+using Controllers.Extensions;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+builder.Services.AddDbConnectionService(builder.Configuration);
+builder.Services.AddRepos();
+builder.Services.AddDomainServices();
+
+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.MigrateDb();
+
+app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+await app.RunAsync();
diff --git a/back/Controllers/Properties/launchSettings.json b/back/Controllers/Properties/launchSettings.json
new file mode 100644
index 0000000..3683563
--- /dev/null
+++ b/back/Controllers/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:47535",
+ "sslPort": 44340
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5125",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7189;http://localhost:5125",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/back/Controllers/appsettings.Development.json b/back/Controllers/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/back/Controllers/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/back/Controllers/appsettings.json b/back/Controllers/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/back/Controllers/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs
new file mode 100644
index 0000000..d787750
--- /dev/null
+++ b/back/Infrastructure/DatabaseContext.cs
@@ -0,0 +1,18 @@
+using Contracts.DTO;
+using Infrastructure.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace Infrastructure;
+
+public class DatabaseContext : DbContext
+{
+ public DatabaseContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ public DbSet Users { get; set; } = null!;
+ public DbSet SpendingGroups { get; set; } = null!;
+ public DbSet ChangeRecords { get; set; } = null!;
+ public DbSet SpendingPlans { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/back/Infrastructure/DbContextFactory.cs b/back/Infrastructure/DbContextFactory.cs
new file mode 100644
index 0000000..00e1443
--- /dev/null
+++ b/back/Infrastructure/DbContextFactory.cs
@@ -0,0 +1,20 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Infrastructure;
+
+public class DbContextFactory : IDbContextFactory
+{
+ private readonly IServiceProvider _serviceProvider;
+
+ public DbContextFactory(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public DatabaseContext CreateDbContext()
+ {
+ var scope = _serviceProvider.CreateScope();
+ return scope.ServiceProvider.GetRequiredService();
+ }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Infrastructure.csproj b/back/Infrastructure/Infrastructure.csproj
new file mode 100644
index 0000000..0d0625a
--- /dev/null
+++ b/back/Infrastructure/Infrastructure.csproj
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/back/Infrastructure/Migrations/20241125164748_User.Designer.cs b/back/Infrastructure/Migrations/20241125164748_User.Designer.cs
new file mode 100644
index 0000000..9872477
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241125164748_User.Designer.cs
@@ -0,0 +1,52 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20241125164748_User")]
+ partial class User
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241125164748_User.cs b/back/Infrastructure/Migrations/20241125164748_User.cs
new file mode 100644
index 0000000..f35370d
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241125164748_User.cs
@@ -0,0 +1,36 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class User : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Users",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ Password = table.Column(type: "text", nullable: false),
+ Balance = table.Column(type: "numeric", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Users", x => x.Id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Users");
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs
new file mode 100644
index 0000000..0ae4d47
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs
@@ -0,0 +1,88 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20241126140310_SpendingGroup")]
+ partial class SpendingGroup
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SpendingGroups");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("SpendingGroups")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Navigation("SpendingGroups");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs
new file mode 100644
index 0000000..1632633
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs
@@ -0,0 +1,46 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class SpendingGroup : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "SpendingGroups",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ UserId = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_SpendingGroups", x => x.Id);
+ table.ForeignKey(
+ name: "FK_SpendingGroups_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_SpendingGroups_UserId",
+ table: "SpendingGroups",
+ column: "UserId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "SpendingGroups");
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs
new file mode 100644
index 0000000..fc60907
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs
@@ -0,0 +1,134 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20241126185002_AddChangeRecord")]
+ partial class AddChangeRecord
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ChangedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ChangeRecords");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SpendingGroups");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany()
+ .HasForeignKey("SpendingGroupId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("SpendingGroups")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Navigation("SpendingGroups");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs
new file mode 100644
index 0000000..0f8a61d
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs
@@ -0,0 +1,59 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class AddChangeRecord : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "ChangeRecords",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Sum = table.Column(type: "numeric", nullable: false),
+ ChangedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UserId = table.Column(type: "uuid", nullable: false),
+ SpendingGroupId = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ChangeRecords", x => x.Id);
+ table.ForeignKey(
+ name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId",
+ column: x => x.SpendingGroupId,
+ principalTable: "SpendingGroups",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_ChangeRecords_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ChangeRecords_SpendingGroupId",
+ table: "ChangeRecords",
+ column: "SpendingGroupId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ChangeRecords_UserId",
+ table: "ChangeRecords",
+ column: "UserId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "ChangeRecords");
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs
new file mode 100644
index 0000000..937117a
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs
@@ -0,0 +1,139 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20241126210947_fixChangeRecord")]
+ partial class fixChangeRecord
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ChangedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ChangeRecords");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SpendingGroups");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("SpendingGroupId");
+
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("SpendingGroups")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Navigation("ChangeRecords");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Navigation("ChangeRecords");
+
+ b.Navigation("SpendingGroups");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs
new file mode 100644
index 0000000..68c6484
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs
@@ -0,0 +1,60 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class fixChangeRecord : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId",
+ table: "ChangeRecords");
+
+ migrationBuilder.AlterColumn(
+ name: "SpendingGroupId",
+ table: "ChangeRecords",
+ type: "uuid",
+ nullable: true,
+ oldClrType: typeof(Guid),
+ oldType: "uuid");
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId",
+ table: "ChangeRecords",
+ column: "SpendingGroupId",
+ principalTable: "SpendingGroups",
+ principalColumn: "Id");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId",
+ table: "ChangeRecords");
+
+ migrationBuilder.AlterColumn(
+ name: "SpendingGroupId",
+ table: "ChangeRecords",
+ type: "uuid",
+ nullable: false,
+ defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
+ oldClrType: typeof(Guid),
+ oldType: "uuid",
+ oldNullable: true);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId",
+ table: "ChangeRecords",
+ column: "SpendingGroupId",
+ principalTable: "SpendingGroups",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs
new file mode 100644
index 0000000..e43fe93
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs
@@ -0,0 +1,177 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20241126222847_AddSpendingPlan")]
+ partial class AddSpendingPlan
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ChangedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ChangeRecords");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SpendingGroups");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("EndAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("StartAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.ToTable("SpendingPlans");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("SpendingGroupId");
+
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("SpendingGroups")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany("SpendingPlans")
+ .HasForeignKey("SpendingGroupId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Navigation("ChangeRecords");
+
+ b.Navigation("SpendingPlans");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Navigation("ChangeRecords");
+
+ b.Navigation("SpendingGroups");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs
new file mode 100644
index 0000000..fcc2f3e
--- /dev/null
+++ b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs
@@ -0,0 +1,48 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class AddSpendingPlan : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "SpendingPlans",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ StartAt = table.Column(type: "timestamp with time zone", nullable: false),
+ EndAt = table.Column(type: "timestamp with time zone", nullable: false),
+ Sum = table.Column(type: "numeric", nullable: false),
+ SpendingGroupId = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_SpendingPlans", x => x.Id);
+ table.ForeignKey(
+ name: "FK_SpendingPlans_SpendingGroups_SpendingGroupId",
+ column: x => x.SpendingGroupId,
+ principalTable: "SpendingGroups",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_SpendingPlans_SpendingGroupId",
+ table: "SpendingPlans",
+ column: "SpendingGroupId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "SpendingPlans");
+ }
+ }
+}
diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs
new file mode 100644
index 0000000..93d0295
--- /dev/null
+++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs
@@ -0,0 +1,174 @@
+//
+using System;
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ partial class DatabaseContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ChangedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ChangeRecords");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SpendingGroups");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("EndAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SpendingGroupId")
+ .HasColumnType("uuid");
+
+ b.Property("StartAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Sum")
+ .HasColumnType("numeric");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpendingGroupId");
+
+ b.ToTable("SpendingPlans");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Balance")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("SpendingGroupId");
+
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("ChangeRecords")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.HasOne("Infrastructure.Models.User", "User")
+ .WithMany("SpendingGroups")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b =>
+ {
+ b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup")
+ .WithMany("SpendingPlans")
+ .HasForeignKey("SpendingGroupId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("SpendingGroup");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b =>
+ {
+ b.Navigation("ChangeRecords");
+
+ b.Navigation("SpendingPlans");
+ });
+
+ modelBuilder.Entity("Infrastructure.Models.User", b =>
+ {
+ b.Navigation("ChangeRecords");
+
+ b.Navigation("SpendingGroups");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/back/Infrastructure/Models/Changerecord.cs b/back/Infrastructure/Models/Changerecord.cs
new file mode 100644
index 0000000..60cb92d
--- /dev/null
+++ b/back/Infrastructure/Models/Changerecord.cs
@@ -0,0 +1,24 @@
+using Contracts.DTO;
+
+namespace Infrastructure.Models;
+
+public class ChangeRecord
+{
+ public Guid Id { get; set; }
+ public decimal Sum { get; set; }
+ public DateTime ChangedAt { get; set; }
+
+ public Guid UserId { get; set; }
+ public User User { get; set; } = null!;
+
+ public Guid? SpendingGroupId { get; set; }
+ public SpendingGroup? SpendingGroup { get; set; }
+
+ public void Update(ChangeRecordDto changeRecordDto)
+ {
+ Id = changeRecordDto.Id;
+ Sum = changeRecordDto.Sum;
+ ChangedAt = changeRecordDto.ChangedAt;
+ SpendingGroupId = changeRecordDto.SpendingGroupId;
+ }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Models/SpendingGroup.cs b/back/Infrastructure/Models/SpendingGroup.cs
new file mode 100644
index 0000000..23758eb
--- /dev/null
+++ b/back/Infrastructure/Models/SpendingGroup.cs
@@ -0,0 +1,12 @@
+namespace Infrastructure.Models;
+
+public class SpendingGroup
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+
+ public Guid UserId { get; set; }
+ public User User { get; set; } = null!;
+ public List? ChangeRecords { get; set; }
+ public List? SpendingPlans { get; set; }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Models/SpendingPlan.cs b/back/Infrastructure/Models/SpendingPlan.cs
new file mode 100644
index 0000000..8162016
--- /dev/null
+++ b/back/Infrastructure/Models/SpendingPlan.cs
@@ -0,0 +1,22 @@
+using Contracts.DTO;
+
+namespace Infrastructure.Models;
+
+public class SpendingPlan
+{
+ public Guid Id { get; set; }
+ public DateTime StartAt { get; set; }
+ public DateTime EndAt { get; set; }
+ public decimal Sum { get; set; }
+
+ public Guid SpendingGroupId { get; set; }
+ public SpendingGroup SpendingGroup { get; set; } = null!;
+
+ public void Update(SpendingPlanDto spendingPlan)
+ {
+ StartAt = spendingPlan.StartAt;
+ EndAt = spendingPlan.EndAt;
+ Sum = spendingPlan.Sum;
+ SpendingGroupId = spendingPlan.SpendingGroupId;
+ }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Models/User.cs b/back/Infrastructure/Models/User.cs
new file mode 100644
index 0000000..469e15e
--- /dev/null
+++ b/back/Infrastructure/Models/User.cs
@@ -0,0 +1,27 @@
+using System.Reflection.Metadata.Ecma335;
+using Contracts.DTO;
+
+namespace Infrastructure.Models;
+
+public class User
+{
+ public Guid Id { get; set; }
+ public string Name { get; set; } = null!;
+ public string Password { get; set; } = null!;
+ public decimal Balance { get; set; }
+ public List? SpendingGroups { get; set; }
+ public List? ChangeRecords { get; set; }
+
+ public void Update(UserDto userDto)
+ {
+ Id = userDto.Id;
+ if (!string.IsNullOrWhiteSpace(userDto.Name))
+ {
+ Name = userDto.Name;
+ }
+ if (!string.IsNullOrWhiteSpace(userDto.Password))
+ {
+ Password = userDto.Password;
+ }
+ }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Repositories/ChangeRecordRepo.cs b/back/Infrastructure/Repositories/ChangeRecordRepo.cs
new file mode 100644
index 0000000..289d89e
--- /dev/null
+++ b/back/Infrastructure/Repositories/ChangeRecordRepo.cs
@@ -0,0 +1,98 @@
+using Contracts.DTO;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Infrastructure.Support.Mappers;
+using Microsoft.EntityFrameworkCore;
+
+namespace Infrastructure.Repositories;
+
+public class ChangeRecordRepo : IChangeRecordRepo
+{
+ public readonly IDbContextFactory _factory;
+
+ public ChangeRecordRepo(IDbContextFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public async Task Create(ChangeRecordDto changeRecord)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var createdRecord = await context.ChangeRecords.AddAsync(changeRecord.ToModel());
+
+ await context.SaveChangesAsync();
+ return createdRecord.Entity.ToDto();
+ }
+
+ public async Task Delete(ChangeRecordSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var record = await context.ChangeRecords
+ .FirstOrDefaultAsync(x => x.Id == search.Id);
+ if (record == null)
+ {
+ return null;
+ }
+
+ context.ChangeRecords.Remove(record);
+ await context.SaveChangesAsync();
+ return record.ToDto();
+ }
+
+ public async Task Get(ChangeRecordSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var record = await context.ChangeRecords
+ .FirstOrDefaultAsync(x => x.Id == search.Id);
+ if (record == null)
+ {
+ return null;
+ }
+ return record.ToDto();
+ }
+
+ public async Task> GetList(ChangeRecordSearch? search = null)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var query = context.ChangeRecords.AsQueryable();
+
+ if (search != null)
+ {
+ if (search.SpendingGroupId.HasValue)
+ {
+ query = query.Where(x => x.SpendingGroupId == search.SpendingGroupId);
+ }
+ if (search.From.HasValue && search.To.HasValue)
+ {
+ query = query.Where(x => x.ChangedAt >= search.From && x.ChangedAt <= search.To);
+ }
+ if (search.UserId.HasValue)
+ {
+ query = query.Where(x => x.UserId == search.UserId);
+ }
+ }
+ return await query.Include(x => x.SpendingGroup).Select(x => x.ToDto()).ToListAsync();
+ }
+
+ public async Task Update(ChangeRecordDto changeRecord)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var existingRecord = await context.ChangeRecords
+ .FirstOrDefaultAsync(x => x.Id == changeRecord.Id);
+
+ if (existingRecord == null)
+ {
+ return null;
+ }
+
+ existingRecord.Update(changeRecord);
+ context.ChangeRecords.Update(existingRecord);
+ await context.SaveChangesAsync();
+ return existingRecord.ToDto();
+ }
+}
diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs
new file mode 100644
index 0000000..e35215f
--- /dev/null
+++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs
@@ -0,0 +1,103 @@
+using Contracts.DTO;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Infrastructure.Support.Mappers;
+using Microsoft.EntityFrameworkCore;
+
+namespace Infrastructure.Repositories;
+
+public class SpendingGroupRepo : ISpendingGroupRepo
+{
+ public readonly IDbContextFactory _factory;
+
+ public SpendingGroupRepo(IDbContextFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public async Task Create(SpendingGroupDto spendingGroup)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var createdGroup = await context.SpendingGroups.AddAsync(spendingGroup.ToModel());
+ await context.SaveChangesAsync();
+ return createdGroup.Entity.ToDto();
+ }
+
+ public async Task Delete(SpendingGroupSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var group = await context.SpendingGroups
+ .FirstOrDefaultAsync(x => x.Id == search.Id
+ || x.Name == search.Name);
+ if (group == null)
+ {
+ return null;
+ }
+
+ context.SpendingGroups.Remove(group);
+ await context.SaveChangesAsync();
+ return group.ToDto();
+ }
+
+ public async Task Get(SpendingGroupSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var group = await context.SpendingGroups
+ .Include(x => x.ChangeRecords)
+ .Include(x => x.SpendingPlans)
+ .FirstOrDefaultAsync(x => x.Id == search.Id
+ || (!string.IsNullOrWhiteSpace(search.Name)
+ && x.Name == search.Name
+ && x.UserId == search.UserId));
+
+ return group?.ToDto();
+ }
+
+ public async Task> GetList(SpendingGroupSearch? search = null)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var query = context.SpendingGroups.AsQueryable();
+
+ if (search != null)
+ {
+ if (search.Id != null)
+ {
+ query = query.Where(x => x.Id == search.Id);
+ }
+
+ if (!string.IsNullOrWhiteSpace(search.Name) && search.UserId.HasValue)
+ {
+ query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase)
+ && x.UserId == search.UserId);
+ }
+ }
+
+ return await query
+ .Include(x => x.ChangeRecords)
+ .Include(x => x.SpendingPlans)
+ .Select(x => x.ToDto())
+ .ToListAsync();
+ }
+
+ public async Task Update(SpendingGroupDto spendingGroup)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var existingGroup = await context.SpendingGroups
+ .FirstOrDefaultAsync(x => x.Id == spendingGroup.Id);
+
+ if (existingGroup == null)
+ {
+ return null;
+ }
+
+ existingGroup.Name = spendingGroup.Name;
+ context.SpendingGroups.Update(existingGroup);
+ await context.SaveChangesAsync();
+ return existingGroup.ToDto();
+ }
+}
diff --git a/back/Infrastructure/Repositories/SpendingPlanRepo.cs b/back/Infrastructure/Repositories/SpendingPlanRepo.cs
new file mode 100644
index 0000000..05c03f3
--- /dev/null
+++ b/back/Infrastructure/Repositories/SpendingPlanRepo.cs
@@ -0,0 +1,86 @@
+using Contracts.DTO;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Infrastructure.Support.Mappers;
+using Microsoft.EntityFrameworkCore;
+
+namespace Infrastructure.Repositories;
+
+public class SpendingPlanRepo : ISpendingPlanRepo
+{
+ public readonly IDbContextFactory _factory;
+
+ public SpendingPlanRepo(IDbContextFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public async Task Create(SpendingPlanDto dto)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var plan = await context.SpendingPlans.AddAsync(dto.ToModel());
+
+ await context.SaveChangesAsync();
+ return plan.Entity.ToDto();
+ }
+
+ public async Task Delete(SpendingPlanSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == search.Id);
+
+ if (plan == null)
+ {
+ return null;
+ }
+
+ context.SpendingPlans.Remove(plan);
+ await context.SaveChangesAsync();
+ return plan.ToDto();
+ }
+
+ public async Task Get(SpendingPlanSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == search.Id);
+
+ return plan?.ToDto();
+ }
+
+ public async Task> GetList(SpendingPlanSearch? search = null)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var query = context.SpendingPlans.AsQueryable();
+
+ if (search != null)
+ {
+ if (search.Id != null)
+ {
+ query = query.Where(x => x.Id == search.Id);
+ }
+ }
+
+ return await query.Select(x => x.ToDto()).ToListAsync();
+ }
+
+ public async Task Update(SpendingPlanDto dto)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == dto.Id);
+
+ if (plan == null)
+ {
+ return null;
+ }
+
+ plan.Update(dto);
+ context.SpendingPlans.Update(plan);
+ await context.SaveChangesAsync();
+ return plan.ToDto();
+ }
+}
diff --git a/back/Infrastructure/Repositories/UserRepo.cs b/back/Infrastructure/Repositories/UserRepo.cs
new file mode 100644
index 0000000..e3a450d
--- /dev/null
+++ b/back/Infrastructure/Repositories/UserRepo.cs
@@ -0,0 +1,91 @@
+using Contracts.DTO;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Infrastructure.Support.Mappers;
+using Microsoft.EntityFrameworkCore;
+
+namespace Infrastructure.Repositories;
+
+public class UserRepo : IUserRepo
+{
+ public readonly IDbContextFactory _factory;
+
+ public UserRepo(IDbContextFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public async Task ChangeBalance(UserSearch search, decimal amount)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var user = await context.Users
+ .FirstOrDefaultAsync(x => x.Id == search.Id
+ || x.Name == search.Name);
+
+ if (user == null)
+ {
+ return false;
+ }
+
+ user.Balance += amount;
+ context.Users.Update(user);
+ await context.SaveChangesAsync();
+ return true;
+ }
+
+ public async Task Create(UserDto user)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var createdUser = await context.Users.AddAsync(user.ToModel());
+
+ await context.SaveChangesAsync();
+ return createdUser.Entity.ToDto();
+ }
+
+ public async Task Delete(UserSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var user = await context.Users
+ .FirstOrDefaultAsync(x => x.Id == search.Id
+ || x.Name == search.Name);
+ if (user == null)
+ {
+ return null;
+ }
+
+ context.Users.Remove(user);
+ await context.SaveChangesAsync();
+ return user.ToDto();
+ }
+
+ public async Task Get(UserSearch search)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var user = await context.Users
+ .FirstOrDefaultAsync(x => x.Id == search.Id
+ || x.Name == search.Name);
+
+ return user?.ToDto();
+ }
+
+ public async Task Update(UserDto user)
+ {
+ using var context = _factory.CreateDbContext();
+
+ var existingUser = await context.Users.FirstOrDefaultAsync(x => x.Id == user.Id);
+
+ if (existingUser == null)
+ {
+ return null;
+ }
+
+ existingUser.Update(user);
+ context.Users.Update(existingUser);
+ await context.SaveChangesAsync();
+ return existingUser.ToDto();
+ }
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs
new file mode 100644
index 0000000..6f62cd6
--- /dev/null
+++ b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs
@@ -0,0 +1,28 @@
+using Contracts.DTO;
+using Infrastructure.Models;
+
+namespace Infrastructure.Support.Mappers;
+
+public static class ChangeRecordMapper
+{
+ public static ChangeRecordDto ToDto(this ChangeRecord changeRecord)
+ => new()
+ {
+ Id = changeRecord.Id,
+ Sum = changeRecord.Sum,
+ ChangedAt = changeRecord.ChangedAt,
+ SpendingGroupId = changeRecord.SpendingGroupId,
+ UserId = changeRecord.UserId,
+ SpendingGroupName = changeRecord.SpendingGroup?.Name
+ };
+
+ public static ChangeRecord ToModel(this ChangeRecordDto changeRecord)
+ => new()
+ {
+ Id = changeRecord.Id,
+ Sum = changeRecord.Sum,
+ ChangedAt = changeRecord.ChangedAt,
+ SpendingGroupId = changeRecord.SpendingGroupId,
+ UserId = changeRecord.UserId
+ };
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs
new file mode 100644
index 0000000..9432073
--- /dev/null
+++ b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs
@@ -0,0 +1,24 @@
+using Contracts.DTO;
+using Infrastructure.Models;
+
+namespace Infrastructure.Support.Mappers;
+
+public static class SpendingGroupMapper
+{
+ public static SpendingGroupDto ToDto(this SpendingGroup group)
+ => new()
+ {
+ Id = group.Id,
+ Name = group.Name,
+ UserId = group.UserId,
+ ChangeRecords = group.ChangeRecords?.Select(x => x.ToDto()).ToList() ?? [],
+ SpendingPlans = group.SpendingPlans?.Select(x => x.ToDto()).ToList() ?? []
+ };
+ public static SpendingGroup ToModel(this SpendingGroupDto group)
+ => new()
+ {
+ Id = group.Id,
+ Name = group.Name,
+ UserId = group.UserId
+ };
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs b/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs
new file mode 100644
index 0000000..22fe884
--- /dev/null
+++ b/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs
@@ -0,0 +1,27 @@
+using Contracts.DTO;
+using Infrastructure.Models;
+
+namespace Infrastructure.Support.Mappers;
+
+public static class SpendingPlanMapper
+{
+ public static SpendingPlan ToModel(this SpendingPlanDto plan)
+ => new()
+ {
+ Id = plan.Id,
+ StartAt = plan.StartAt,
+ EndAt = plan.EndAt,
+ Sum = plan.Sum,
+ SpendingGroupId = plan.SpendingGroupId
+ };
+
+ public static SpendingPlanDto ToDto(this SpendingPlan plan)
+ => new()
+ {
+ Id = plan.Id,
+ StartAt = plan.StartAt,
+ EndAt = plan.EndAt,
+ Sum = plan.Sum,
+ SpendingGroupId = plan.SpendingGroupId
+ };
+}
\ No newline at end of file
diff --git a/back/Infrastructure/Support/Mappers/UserMapper.cs b/back/Infrastructure/Support/Mappers/UserMapper.cs
new file mode 100644
index 0000000..02e47fc
--- /dev/null
+++ b/back/Infrastructure/Support/Mappers/UserMapper.cs
@@ -0,0 +1,25 @@
+using Contracts.DTO;
+using Infrastructure.Models;
+
+namespace Infrastructure.Support.Mappers;
+
+public static class UserMapper
+{
+ public static UserDto ToDto(this User user)
+ => new()
+ {
+ Id = user.Id,
+ Name = user.Name,
+ Balance = user.Balance,
+ Password = user.Password
+ };
+
+ public static User ToModel(this UserDto user)
+ => new()
+ {
+ Id = user.Id,
+ Name = user.Name,
+ Balance = user.Balance,
+ Password = user.Password
+ };
+}
\ No newline at end of file
diff --git a/back/Services/Domain/AuthService.cs b/back/Services/Domain/AuthService.cs
new file mode 100644
index 0000000..c00a47a
--- /dev/null
+++ b/back/Services/Domain/AuthService.cs
@@ -0,0 +1,49 @@
+using Contracts.DTO;
+using Contracts.Mappers;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Services.Support.Exceptions;
+
+namespace Services.Domain;
+
+public class AuthService : IAuthService
+{
+ private readonly IUserRepo _userRepo;
+
+ public AuthService(IUserRepo userRepo)
+ {
+ _userRepo = userRepo;
+ }
+
+ public async Task Login(UserLoginDto loginData)
+ {
+ if (loginData == null || string.IsNullOrWhiteSpace(loginData.Name)
+ || string.IsNullOrWhiteSpace(loginData.Password))
+ {
+ throw new ArgumentException("Неверные данные для входа");
+ }
+
+ var user = await _userRepo.Get(new UserSearch() { Name = loginData.Name });
+ if (user == null)
+ {
+ throw new UserNotFoundException($"Пользователь {loginData.Name} не найден");
+ }
+
+ return user.ToView();
+ }
+
+ public async Task Register(UserDto user)
+ {
+ var existingUser = await _userRepo.Get(new UserSearch() { Name = user.Name });
+ if (existingUser != null)
+ {
+ throw new AlreadyExistsException("Такой пользователь уже существует");
+ }
+
+ var createdUser = await _userRepo.Create(user);
+
+ return createdUser.ToView();
+ }
+}
diff --git a/back/Services/Domain/ChangeRecordService.cs b/back/Services/Domain/ChangeRecordService.cs
new file mode 100644
index 0000000..45ed858
--- /dev/null
+++ b/back/Services/Domain/ChangeRecordService.cs
@@ -0,0 +1,59 @@
+using Contracts.DTO;
+using Contracts.Mappers;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+
+namespace Services.Domain;
+
+public class ChangeRecordService : IChangeRecordService
+{
+ private readonly IChangeRecordRepo _changeRecordRepo;
+ private readonly IUserRepo _userRepo;
+
+ public ChangeRecordService(IChangeRecordRepo changeRecordRepo, IUserRepo userRepo)
+ {
+ _changeRecordRepo = changeRecordRepo;
+ _userRepo = userRepo;
+ }
+
+ public async Task Create(ChangeRecordDto model)
+ {
+ var record = await _changeRecordRepo.Create(model);
+
+ await _userRepo.ChangeBalance(new() { Id = model.UserId }, model.Sum);
+
+ return record.ToView();
+ }
+
+ public async Task Delete(ChangeRecordSearch search)
+ {
+ var record = await _changeRecordRepo.Delete(search);
+ if (record == null)
+ {
+ throw new EntryPointNotFoundException("При удалении не получилось найти запись измнения баланса");
+ }
+ // Возвращает баланс обратно
+ await _userRepo.ChangeBalance(new() { Id = record.UserId }, -record.Sum);
+ return record.ToView();
+ }
+
+ public async Task> GetList(ChangeRecordSearch? search = null)
+ {
+ var records = await _changeRecordRepo.GetList(search);
+
+ return records.Select(x => x.ToView()).ToList();
+ }
+
+ public async Task Update(ChangeRecordDto model)
+ {
+ var record = await _changeRecordRepo.Update(model);
+ if (record == null)
+ {
+ throw new EntryPointNotFoundException("При изменении не получилось найти запись измнения баланса");
+ }
+ await _userRepo.ChangeBalance(new() { Id = model.UserId }, model.Sum - record.Sum);
+ return record.ToView();
+ }
+}
diff --git a/back/Services/Domain/SpendingGroupService.cs b/back/Services/Domain/SpendingGroupService.cs
new file mode 100644
index 0000000..e4ff348
--- /dev/null
+++ b/back/Services/Domain/SpendingGroupService.cs
@@ -0,0 +1,63 @@
+using Contracts.DTO;
+using Contracts.Mappers;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Contracts.ViewModels;
+using Services.Support.Exceptions;
+
+namespace Contracts.Services;
+
+public class SpendingGroupService : ISpendingGroupService
+{
+ private readonly ISpendingGroupRepo _spendingGroupRepo;
+
+ public SpendingGroupService(ISpendingGroupRepo spendingGroupRepo)
+ {
+ _spendingGroupRepo = spendingGroupRepo;
+ }
+
+ public async Task Create(SpendingGroupDto model)
+ {
+ var group = await _spendingGroupRepo.Create(model);
+ return group.ToView();
+ }
+
+ public async Task Delete(SpendingGroupSearch search)
+ {
+ var group = await _spendingGroupRepo.Delete(search);
+ if (group == null)
+ {
+ throw new EntityNotFoundException("При удалении не получилось найти группу");
+ }
+
+ return group.ToView();
+ }
+
+ public async Task GetDetails(SpendingGroupSearch search)
+ {
+ var group = await _spendingGroupRepo.Get(search);
+ if (group == null)
+ {
+ throw new EntityNotFoundException("Не удалось найти группу по таким параметрам");
+ }
+
+ return group.ToView();
+ }
+
+ public async Task> GetList(SpendingGroupSearch? search = null)
+ {
+ var groups = await _spendingGroupRepo.GetList(search);
+ return groups.Select(x => x.ToView()).ToList();
+ }
+
+ public async Task Update(SpendingGroupDto model)
+ {
+ var group = await _spendingGroupRepo.Update(model);
+ if (group == null)
+ {
+ throw new EntityNotFoundException("При обновлении не получилось найти группу");
+ }
+
+ return group.ToView();
+ }
+}
diff --git a/back/Services/Domain/SpendingPlanService.cs b/back/Services/Domain/SpendingPlanService.cs
new file mode 100644
index 0000000..ff655d0
--- /dev/null
+++ b/back/Services/Domain/SpendingPlanService.cs
@@ -0,0 +1,61 @@
+using Contracts.DTO;
+using Contracts.Mappers;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Services.Support.Exceptions;
+
+namespace Services.Domain;
+
+public class SpendingPlanService : ISpendingPlanService
+{
+ private readonly ISpendingPlanRepo _spendingPlanRepo;
+
+ public SpendingPlanService(ISpendingPlanRepo spendingPlanRepo)
+ {
+ _spendingPlanRepo = spendingPlanRepo;
+ }
+
+ public async Task Create(SpendingPlanDto spendingPlan)
+ {
+ var plan = await _spendingPlanRepo.Create(spendingPlan);
+ return plan.ToView();
+ }
+
+ public async Task Delete(SpendingPlanSearch search)
+ {
+ var plan = await _spendingPlanRepo.Delete(search);
+ if (plan == null)
+ {
+ throw new EntityNotFoundException("При удалении не получилось найти план");
+ }
+ return plan.ToView();
+ }
+
+ public async Task GetDetails(SpendingPlanSearch search)
+ {
+ var plan = await _spendingPlanRepo.Get(search);
+ if (plan == null)
+ {
+ throw new EntityNotFoundException("Не удалось найти план по таким параметрам");
+ }
+ return plan.ToView();
+ }
+
+ public async Task> GetList(SpendingPlanSearch? search = null)
+ {
+ var plans = await _spendingPlanRepo.GetList(search);
+ return plans.Select(x => x.ToView()).ToList();
+ }
+
+ public async Task Update(SpendingPlanDto spendingPlan)
+ {
+ var plan = await _spendingPlanRepo.Update(spendingPlan);
+ if (plan == null)
+ {
+ throw new EntityNotFoundException("При обновлении не получилось найти план");
+ }
+ return plan.ToView();
+ }
+}
diff --git a/back/Services/Domain/UserService.cs b/back/Services/Domain/UserService.cs
new file mode 100644
index 0000000..5f6f2c5
--- /dev/null
+++ b/back/Services/Domain/UserService.cs
@@ -0,0 +1,49 @@
+using Contracts.DTO;
+using Contracts.Mappers;
+using Contracts.Repositories;
+using Contracts.SearchModels;
+using Contracts.Services;
+using Contracts.ViewModels;
+using Services.Support.Exceptions;
+
+namespace Services.Domain;
+
+public class UserService : IUserService
+{
+ private readonly IUserRepo _userRepo;
+
+ public UserService(IUserRepo userRepo)
+ {
+ _userRepo = userRepo;
+ }
+
+ public async Task Delete(UserSearch search)
+ {
+ var user = await _userRepo.Delete(search);
+ if (user == null)
+ {
+ throw new UserNotFoundException($"Пользователь для удаления не найден");
+ }
+ return user.ToView();
+ }
+
+ public async Task GetDetails(UserSearch search)
+ {
+ var user = await _userRepo.Get(search);
+ if (user == null)
+ {
+ throw new UserNotFoundException($"Пользователь {search.Name} не найден");
+ }
+ return user.ToView();
+ }
+
+ public async Task UpdateUserData(UserDto user)
+ {
+ var updatedUser = await _userRepo.Update(user);
+ if (updatedUser == null)
+ {
+ throw new EntityNotFoundException("При обновлении не получилось найти пользователя с id = " + user.Id);
+ }
+ return updatedUser.ToView();
+ }
+}
diff --git a/back/Services/Services.csproj b/back/Services/Services.csproj
new file mode 100644
index 0000000..3c22415
--- /dev/null
+++ b/back/Services/Services.csproj
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/back/Services/Support/Exceptions/AlreadyExistsException.cs b/back/Services/Support/Exceptions/AlreadyExistsException.cs
new file mode 100644
index 0000000..8577218
--- /dev/null
+++ b/back/Services/Support/Exceptions/AlreadyExistsException.cs
@@ -0,0 +1,9 @@
+namespace Services.Support.Exceptions;
+
+public class AlreadyExistsException : Exception
+{
+ public AlreadyExistsException(string message) : base(message) { }
+
+ public AlreadyExistsException(string message, Exception innerException)
+ : base(message, innerException) { }
+}
\ No newline at end of file
diff --git a/back/Services/Support/Exceptions/EntityNotFoundException.cs b/back/Services/Support/Exceptions/EntityNotFoundException.cs
new file mode 100644
index 0000000..957b0b3
--- /dev/null
+++ b/back/Services/Support/Exceptions/EntityNotFoundException.cs
@@ -0,0 +1,10 @@
+namespace Services.Support.Exceptions;
+
+public class EntityNotFoundException : Exception
+{
+ public EntityNotFoundException(string message)
+ : base(message) { }
+ public EntityNotFoundException(string message, Exception innerException)
+ : base(message, innerException) { }
+
+}
\ No newline at end of file
diff --git a/back/Services/Support/Exceptions/UserNotFoundException.cs b/back/Services/Support/Exceptions/UserNotFoundException.cs
new file mode 100644
index 0000000..77b2297
--- /dev/null
+++ b/back/Services/Support/Exceptions/UserNotFoundException.cs
@@ -0,0 +1,12 @@
+using Contracts.SearchModels;
+
+namespace Services.Support.Exceptions;
+
+public class UserNotFoundException : EntityNotFoundException
+{
+ public UserNotFoundException(string message)
+ : base(message) { }
+ public UserNotFoundException(string message, Exception innerException)
+ : base(message, innerException) { }
+
+}
\ No newline at end of file
diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml
new file mode 100644
index 0000000..02d8292
--- /dev/null
+++ b/docker-compose.debug.yml
@@ -0,0 +1,41 @@
+# Please refer https://aka.ms/HTTPSinContainer on how to setup an https developer certificate for your ASP.NET Core service.
+services:
+ api:
+ image: api
+ build:
+ context: .
+ dockerfile: back/Controllers/Dockerfile
+ args:
+ - configuration=Debug
+ ports:
+ - 5125:5125
+ environment:
+ - ConnectionStrings__DefaultConnection=${CONNECTION_STRING}
+ - ASPNETCORE_ENVIRONMENT=Development
+ volumes:
+ - ~/.vsdbg:/remote_debugger:rw
+ depends_on:
+ - database
+ dombudg:
+ image: dombudg
+ build:
+ context: front
+ dockerfile: ./Dockerfile
+ environment:
+ - VITE_API_URL=http://api:5125
+ ports:
+ - 80:80
+ depends_on:
+ - api
+ database:
+ image: postgres:14
+ environment:
+ - POSTGRES_DB=${POSTGRES_DB}
+ - POSTGRES_USER=${POSTGRES_USER}
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+volumes:
+ postgres_data:
+ driver: local
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..284a658
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,35 @@
+services:
+ api:
+ image: api
+ build:
+ context: .
+ dockerfile: back/Controllers/Dockerfile
+ ports:
+ - 5125:5125
+ environment:
+ - ConnectionStrings__DefaultConnection=${CONNECTION_STRING}
+ depends_on:
+ - database
+ dombudg:
+ image: dombudg
+ build:
+ context: front
+ dockerfile: ./Dockerfile
+ environment:
+ - VITE_API_URL=http://api:5125
+ ports:
+ - 80:80
+ depends_on:
+ - api
+ database:
+ image: postgres:14
+ environment:
+ - POSTGRES_DB=${POSTGRES_DB}
+ - POSTGRES_USER=${POSTGRES_USER}
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+volumes:
+ postgres_data:
+ driver: local
\ No newline at end of file
diff --git a/front/.dockerignore b/front/.dockerignore
new file mode 100644
index 0000000..809ba83
--- /dev/null
+++ b/front/.dockerignore
@@ -0,0 +1,24 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/charts
+**/docker-compose*
+**/compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
diff --git a/front/.gitignore b/front/.gitignore
new file mode 100644
index 0000000..3b0b403
--- /dev/null
+++ b/front/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+.env
\ No newline at end of file
diff --git a/front/Dockerfile b/front/Dockerfile
new file mode 100644
index 0000000..89d6bcc
--- /dev/null
+++ b/front/Dockerfile
@@ -0,0 +1,18 @@
+FROM node as vite-app
+
+ARG VITE_API_URL
+
+WORKDIR /app/client
+COPY . .
+
+RUN ["npm", "i"]
+RUN ["npm", "run", "build"]
+
+FROM nginx:alpine
+
+COPY nginx.conf /etc/nginx
+
+RUN rm -rf /usr/share/nginx/html/*
+COPY --from=vite-app /app/client/dist /usr/share/nginx/html
+
+ENTRYPOINT ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/front/components.d.ts b/front/components.d.ts
new file mode 100644
index 0000000..55d7595
--- /dev/null
+++ b/front/components.d.ts
@@ -0,0 +1,38 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+ export interface GlobalComponents {
+ AButton: typeof import('ant-design-vue/es')['Button']
+ ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
+ AForm: typeof import('ant-design-vue/es')['Form']
+ AFormItem: typeof import('ant-design-vue/es')['FormItem']
+ AInput: typeof import('ant-design-vue/es')['Input']
+ AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
+ AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
+ ALayout: typeof import('ant-design-vue/es')['Layout']
+ ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
+ ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
+ APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
+ ASelect: typeof import('ant-design-vue/es')['Select']
+ ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
+ ASpace: typeof import('ant-design-vue/es')['Space']
+ ASpin: typeof import('ant-design-vue/es')['Spin']
+ ATable: typeof import('ant-design-vue/es')['Table']
+ ChangeRecordManager: typeof import('./src/components/support/ChangeRecordManager.vue')['default']
+ Groups: typeof import('./src/components/pages/Groups.vue')['default']
+ Header: typeof import('./src/components/main/Header.vue')['default']
+ Home: typeof import('./src/components/pages/Home.vue')['default']
+ Login: typeof import('./src/components/pages/Login.vue')['default']
+ PlanManager: typeof import('./src/components/support/PlanManager.vue')['default']
+ Plans: typeof import('./src/components/pages/Plans.vue')['default']
+ RouterLink: typeof import('vue-router')['RouterLink']
+ RouterView: typeof import('vue-router')['RouterView']
+ SignUp: typeof import('./src/components/pages/SignUp.vue')['default']
+ SpendingGroupManager: typeof import('./src/components/support/SpendingGroupManager.vue')['default']
+ }
+}
diff --git a/front/index.html b/front/index.html
new file mode 100644
index 0000000..28e68e6
--- /dev/null
+++ b/front/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ ДомБюдж
+
+
+
+
+
+
diff --git a/front/nginx.conf b/front/nginx.conf
new file mode 100644
index 0000000..e24cefe
--- /dev/null
+++ b/front/nginx.conf
@@ -0,0 +1,55 @@
+# Запускать в качестве менее привилегированного пользователя по соображениям безопасности..
+user nginx;
+
+# Значение auto устанавливает число максимально доступных ядер CPU,
+# чтобы обеспечить лучшую производительность.
+worker_processes auto;
+
+events { worker_connections 1024; }
+
+http {
+ server {
+ # Hide nginx version information.
+ server_tokens off;
+
+ listen 80;
+ root /usr/share/nginx/html;
+ include /etc/nginx/mime.types;
+
+ location /api/ {
+ proxy_pass http://api:5125/api/;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-Prefix /test;
+ }
+
+ location / {
+ try_files $uri $uri/ /index.html;
+ }
+
+ gzip on;
+ gzip_vary on;
+ gzip_http_version 1.0;
+ gzip_comp_level 5;
+ gzip_types
+ application/atom+xml
+ application/javascript
+ application/json
+ application/rss+xml
+ application/vnd.ms-fontobject
+ application/x-font-ttf
+ application/x-web-app-manifest+json
+ application/xhtml+xml
+ application/xml
+ font/opentype
+ image/svg+xml
+ image/x-icon
+ text/css
+ text/plain
+ text/x-component;
+ gzip_proxied no-cache no-store private expired auth;
+ gzip_min_length 256;
+ gunzip on;
+ }
+}
\ No newline at end of file
diff --git a/front/package-lock.json b/front/package-lock.json
new file mode 100644
index 0000000..c1ae6fb
--- /dev/null
+++ b/front/package-lock.json
@@ -0,0 +1,3000 @@
+{
+ "name": "dombudg",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "dombudg",
+ "version": "0.0.0",
+ "dependencies": {
+ "@vueuse/core": "^12.0.0",
+ "ant-design-vue": "^4.2.6",
+ "dayjs": "^1.11.13",
+ "pinia": "^2.2.8",
+ "vue": "^3.5.12",
+ "vue-router": "^4.5.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.1.4",
+ "swagger-typescript-api": "^13.0.23",
+ "typescript": "~5.6.2",
+ "unplugin-vue-components": "^0.27.5",
+ "vite": "^5.4.10",
+ "vue-tsc": "^2.1.8"
+ }
+ },
+ "node_modules/@ant-design/colors": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
+ "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@ctrl/tinycolor": "^3.4.0"
+ }
+ },
+ "node_modules/@ant-design/icons-svg": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
+ "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==",
+ "license": "MIT"
+ },
+ "node_modules/@ant-design/icons-vue": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-7.0.1.tgz",
+ "integrity": "sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/colors": "^6.0.0",
+ "@ant-design/icons-svg": "^4.2.1"
+ },
+ "peerDependencies": {
+ "vue": ">=3.0.3"
+ }
+ },
+ "node_modules/@antfu/utils": {
+ "version": "0.7.10",
+ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+ "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz",
+ "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.26.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+ "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
+ "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@ctrl/tinycolor": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
+ "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
+ "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==",
+ "license": "MIT"
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@exodus/schemasafe": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz",
+ "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz",
+ "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz",
+ "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz",
+ "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz",
+ "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz",
+ "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz",
+ "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz",
+ "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz",
+ "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz",
+ "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz",
+ "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz",
+ "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz",
+ "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz",
+ "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz",
+ "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz",
+ "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz",
+ "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz",
+ "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz",
+ "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz",
+ "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@simonwep/pickr": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz",
+ "integrity": "sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-js": "^3.15.1",
+ "nanopop": "^2.1.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/swagger-schema-official": {
+ "version": "2.0.25",
+ "resolved": "https://registry.npmjs.org/@types/swagger-schema-official/-/swagger-schema-official-2.0.25.tgz",
+ "integrity": "sha512-T92Xav+Gf/Ik1uPW581nA+JftmjWPgskw/WBf4TJzxRG/SJ+DfNnNE+WuZ4mrXuzflQMqMkm1LSYjzYW7MB1Cg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/web-bluetooth": {
+ "version": "0.0.20",
+ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
+ "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
+ "license": "MIT"
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz",
+ "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.10",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.10.tgz",
+ "integrity": "sha512-hG3Z13+nJmGaT+fnQzAkS0hjJRa2FCeqZt6Bd+oGNhUkQ+mTFsDETg5rqUTxyzIh5pSOGY7FHCWUS8G82AzLCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.10"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.10",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.10.tgz",
+ "integrity": "sha512-OCV+b5ihV0RF3A7vEvNyHPi4G4kFa6ukPmyVocmqm5QzOd8r5yAtiNvaPEjl8dNvgC/lj4JPryeeHLdXd62rWA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.10",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.10.tgz",
+ "integrity": "sha512-F8ZtBMhSXyYKuBfGpYwqA5rsONnOwAVvjyE7KPYJ7wgZqo2roASqNWUnianOomJX5u1cxeRooHV59N0PhvEOgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.10",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz",
+ "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/shared": "3.5.13",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz",
+ "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.13",
+ "@vue/shared": "3.5.13"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz",
+ "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/compiler-core": "3.5.13",
+ "@vue/compiler-dom": "3.5.13",
+ "@vue/compiler-ssr": "3.5.13",
+ "@vue/shared": "3.5.13",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.11",
+ "postcss": "^8.4.48",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz",
+ "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.13",
+ "@vue/shared": "3.5.13"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+ "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+ "license": "MIT"
+ },
+ "node_modules/@vue/language-core": {
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz",
+ "integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "~2.4.8",
+ "@vue/compiler-dom": "^3.5.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.5.0",
+ "alien-signals": "^0.2.0",
+ "minimatch": "^9.0.3",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz",
+ "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.13"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz",
+ "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.13",
+ "@vue/shared": "3.5.13"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz",
+ "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.13",
+ "@vue/runtime-core": "3.5.13",
+ "@vue/shared": "3.5.13",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz",
+ "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.13",
+ "@vue/shared": "3.5.13"
+ },
+ "peerDependencies": {
+ "vue": "3.5.13"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz",
+ "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
+ "license": "MIT"
+ },
+ "node_modules/@vueuse/core": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz",
+ "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.20",
+ "@vueuse/metadata": "12.0.0",
+ "@vueuse/shared": "12.0.0",
+ "vue": "^3.5.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/metadata": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz",
+ "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/shared": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz",
+ "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==",
+ "license": "MIT",
+ "dependencies": {
+ "vue": "^3.5.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/alien-signals": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.2.2.tgz",
+ "integrity": "sha512-cZIRkbERILsBOXTQmMrxc9hgpxglstn69zm+F1ARf4aPAzdAFYd6sBq87ErO0Fj3DV94tglcyHG5kQz9nDC/8A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ant-design-vue": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-4.2.6.tgz",
+ "integrity": "sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/colors": "^6.0.0",
+ "@ant-design/icons-vue": "^7.0.0",
+ "@babel/runtime": "^7.10.5",
+ "@ctrl/tinycolor": "^3.5.0",
+ "@emotion/hash": "^0.9.0",
+ "@emotion/unitless": "^0.8.0",
+ "@simonwep/pickr": "~1.8.0",
+ "array-tree-filter": "^2.1.0",
+ "async-validator": "^4.0.0",
+ "csstype": "^3.1.1",
+ "dayjs": "^1.10.5",
+ "dom-align": "^1.12.1",
+ "dom-scroll-into-view": "^2.0.0",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.15",
+ "resize-observer-polyfill": "^1.5.1",
+ "scroll-into-view-if-needed": "^2.2.25",
+ "shallow-equal": "^1.0.0",
+ "stylis": "^4.1.3",
+ "throttle-debounce": "^5.0.0",
+ "vue-types": "^3.0.0",
+ "warning": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ant-design-vue"
+ },
+ "peerDependencies": {
+ "vue": ">=3.2.0"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/array-tree-filter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
+ "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==",
+ "license": "MIT"
+ },
+ "node_modules/async-validator": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-me-maybe": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/compute-scroll-into-view": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+ "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
+ "license": "MIT"
+ },
+ "node_modules/confbox": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/consola": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz",
+ "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "3.39.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
+ "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "license": "MIT"
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+ "license": "MIT"
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/dom-align": {
+ "version": "1.12.4",
+ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz",
+ "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==",
+ "license": "MIT"
+ },
+ "node_modules/dom-scroll-into-view": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz",
+ "integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==",
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es6-promise": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
+ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/eta": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz",
+ "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/eta-dev/eta?sponsor=1"
+ }
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/http2-client": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz",
+ "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-object": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
+ "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/local-pkg": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz",
+ "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mlly": "^1.7.3",
+ "pkg-types": "^1.2.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+ "license": "MIT"
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.14",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz",
+ "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/micromatch/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/mlly": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.3.tgz",
+ "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.14.0",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.2.1",
+ "ufo": "^1.5.4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/nanopop": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.4.2.tgz",
+ "integrity": "sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==",
+ "license": "MIT"
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch-h2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz",
+ "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "http2-client": "^1.2.5"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/node-readfiles": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz",
+ "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es6-promise": "^3.2.1"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/oas-kit-common": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz",
+ "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "fast-safe-stringify": "^2.0.7"
+ }
+ },
+ "node_modules/oas-linter": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz",
+ "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@exodus/schemasafe": "^1.0.0-rc.2",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-resolver": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz",
+ "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-h2": "^2.3.0",
+ "oas-kit-common": "^1.0.8",
+ "reftools": "^1.1.9",
+ "yaml": "^1.10.0",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "resolve": "resolve.js"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-schema-walker": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz",
+ "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-validator": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz",
+ "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "oas-kit-common": "^1.0.8",
+ "oas-linter": "^3.2.2",
+ "oas-resolver": "^2.5.6",
+ "oas-schema-walker": "^1.1.5",
+ "reftools": "^1.1.9",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pinia": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.8.tgz",
+ "integrity": "sha512-NRTYy2g+kju5tBRe0oNlriZIbMNvma8ZJrpHsp3qudyiMEA8jMmPPKQ2QMHg0Oc4BkUyQYWagACabrwriCK9HQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3",
+ "vue-demi": "^0.14.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.4.0",
+ "typescript": ">=4.4.4",
+ "vue": "^2.6.14 || ^3.5.11"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pinia/node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz",
+ "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.8",
+ "mlly": "^1.7.2",
+ "pathe": "^1.1.2"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.49",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
+ "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/reftools": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz",
+ "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "license": "MIT"
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resize-observer-polyfill": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
+ "license": "MIT"
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.27.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz",
+ "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.27.4",
+ "@rollup/rollup-android-arm64": "4.27.4",
+ "@rollup/rollup-darwin-arm64": "4.27.4",
+ "@rollup/rollup-darwin-x64": "4.27.4",
+ "@rollup/rollup-freebsd-arm64": "4.27.4",
+ "@rollup/rollup-freebsd-x64": "4.27.4",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.27.4",
+ "@rollup/rollup-linux-arm-musleabihf": "4.27.4",
+ "@rollup/rollup-linux-arm64-gnu": "4.27.4",
+ "@rollup/rollup-linux-arm64-musl": "4.27.4",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4",
+ "@rollup/rollup-linux-riscv64-gnu": "4.27.4",
+ "@rollup/rollup-linux-s390x-gnu": "4.27.4",
+ "@rollup/rollup-linux-x64-gnu": "4.27.4",
+ "@rollup/rollup-linux-x64-musl": "4.27.4",
+ "@rollup/rollup-win32-arm64-msvc": "4.27.4",
+ "@rollup/rollup-win32-ia32-msvc": "4.27.4",
+ "@rollup/rollup-win32-x64-msvc": "4.27.4",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/scroll-into-view-if-needed": {
+ "version": "2.2.31",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+ "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+ "license": "MIT",
+ "dependencies": {
+ "compute-scroll-into-view": "^1.0.20"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shallow-equal": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
+ "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==",
+ "license": "MIT"
+ },
+ "node_modules/should": {
+ "version": "13.2.3",
+ "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz",
+ "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-equal": "^2.0.0",
+ "should-format": "^3.0.3",
+ "should-type": "^1.4.0",
+ "should-type-adaptors": "^1.0.1",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-equal": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
+ "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.4.0"
+ }
+ },
+ "node_modules/should-format": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
+ "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-type-adaptors": "^1.0.1"
+ }
+ },
+ "node_modules/should-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
+ "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/should-type-adaptors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz",
+ "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-util": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz",
+ "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylis": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz",
+ "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==",
+ "license": "MIT"
+ },
+ "node_modules/swagger-schema-official": {
+ "version": "2.0.0-bab6bed",
+ "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz",
+ "integrity": "sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/swagger-typescript-api": {
+ "version": "13.0.23",
+ "resolved": "https://registry.npmjs.org/swagger-typescript-api/-/swagger-typescript-api-13.0.23.tgz",
+ "integrity": "sha512-HhoIepxlFEU7Ol42Gh8/tvwhSxdkHcweX2tRkNhbZYBiEA+rK3C6N85MnwoeQR5XbidE3Kz8mLOqIerVGgR9uw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/swagger-schema-official": "^2.0.25",
+ "consola": "^3.2.3",
+ "cosmiconfig": "^9.0.0",
+ "didyoumean": "^1.2.2",
+ "eta": "^2.2.0",
+ "js-yaml": "^4.1.0",
+ "lodash": "^4.17.21",
+ "nanoid": "^3.3.7",
+ "prettier": "~3.3.3",
+ "swagger-schema-official": "2.0.0-bab6bed",
+ "swagger2openapi": "^7.0.8",
+ "typescript": "~5.5.4"
+ },
+ "bin": {
+ "sta": "dist/cli.js",
+ "swagger-typescript-api": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/swagger-typescript-api/node_modules/typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/swagger2openapi": {
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz",
+ "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "node-fetch": "^2.6.1",
+ "node-fetch-h2": "^2.3.0",
+ "node-readfiles": "^0.2.0",
+ "oas-kit-common": "^1.0.8",
+ "oas-resolver": "^2.5.6",
+ "oas-schema-walker": "^1.1.5",
+ "oas-validator": "^5.0.8",
+ "reftools": "^1.1.9",
+ "yaml": "^1.10.0",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "boast": "boast.js",
+ "oas-validate": "oas-validate.js",
+ "swagger2openapi": "swagger2openapi.js"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/throttle-debounce": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+ "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.22"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/typescript": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unplugin": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.0.tgz",
+ "integrity": "sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.14.0",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/unplugin-vue-components": {
+ "version": "0.27.5",
+ "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz",
+ "integrity": "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@antfu/utils": "^0.7.10",
+ "@rollup/pluginutils": "^5.1.3",
+ "chokidar": "^3.6.0",
+ "debug": "^4.3.7",
+ "fast-glob": "^3.3.2",
+ "local-pkg": "^0.5.1",
+ "magic-string": "^0.30.14",
+ "minimatch": "^9.0.5",
+ "mlly": "^1.7.3",
+ "unplugin": "^1.16.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@babel/parser": "^7.15.8",
+ "@nuxt/kit": "^3.2.2",
+ "vue": "2 || 3"
+ },
+ "peerDependenciesMeta": {
+ "@babel/parser": {
+ "optional": true
+ },
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.4.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
+ "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
+ "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vue": {
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
+ "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.13",
+ "@vue/compiler-sfc": "3.5.13",
+ "@vue/runtime-dom": "3.5.13",
+ "@vue/server-renderer": "3.5.13",
+ "@vue/shared": "3.5.13"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-router": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz",
+ "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vue-tsc": {
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.10.tgz",
+ "integrity": "sha512-RBNSfaaRHcN5uqVqJSZh++Gy/YUzryuv9u1aFWhsammDJXNtUiJMNoJ747lZcQ68wUQFx6E73y4FY3D8E7FGMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/typescript": "~2.4.8",
+ "@vue/language-core": "2.1.10",
+ "semver": "^7.5.4"
+ },
+ "bin": {
+ "vue-tsc": "bin/vue-tsc.js"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.0"
+ }
+ },
+ "node_modules/vue-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz",
+ "integrity": "sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-object": "3.0.1"
+ },
+ "engines": {
+ "node": ">=10.15.0"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/webpack-virtual-modules": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ }
+ }
+}
diff --git a/front/package.json b/front/package.json
new file mode 100644
index 0000000..9dae701
--- /dev/null
+++ b/front/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "dombudg",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vue-tsc -b && vite build",
+ "preview": "vite preview",
+ "gen-api": "swagger-typescript-api -r -o ./src/core/api/ --modular -p "
+ },
+ "dependencies": {
+ "@vueuse/core": "^12.0.0",
+ "ant-design-vue": "^4.2.6",
+ "dayjs": "^1.11.13",
+ "pinia": "^2.2.8",
+ "vue": "^3.5.12",
+ "vue-router": "^4.5.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.1.4",
+ "swagger-typescript-api": "^13.0.23",
+ "typescript": "~5.6.2",
+ "unplugin-vue-components": "^0.27.5",
+ "vite": "^5.4.10",
+ "vue-tsc": "^2.1.8"
+ }
+}
diff --git a/front/src/App.vue b/front/src/App.vue
new file mode 100644
index 0000000..aa38b70
--- /dev/null
+++ b/front/src/App.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue
new file mode 100644
index 0000000..d2d0563
--- /dev/null
+++ b/front/src/components/main/Header.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
diff --git a/front/src/components/pages/Groups.vue b/front/src/components/pages/Groups.vue
new file mode 100644
index 0000000..8781ced
--- /dev/null
+++ b/front/src/components/pages/Groups.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
Группы расходов
+
+
+
+
+ Планы
+
+
+
+ Удалить
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/pages/Home.vue b/front/src/components/pages/Home.vue
new file mode 100644
index 0000000..0285db5
--- /dev/null
+++ b/front/src/components/pages/Home.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
История изменений баланса
+
+
+
+
+
+ Удалить
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/pages/Login.vue b/front/src/components/pages/Login.vue
new file mode 100644
index 0000000..d7a335e
--- /dev/null
+++ b/front/src/components/pages/Login.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Войти
+
+ Или
+ создать аккаунт
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/pages/Plans.vue b/front/src/components/pages/Plans.vue
new file mode 100644
index 0000000..bcdfeb9
--- /dev/null
+++ b/front/src/components/pages/Plans.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
Планы группы
+
+
+
+
+
+ Удалить
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/pages/SignUp.vue b/front/src/components/pages/SignUp.vue
new file mode 100644
index 0000000..dbc03bc
--- /dev/null
+++ b/front/src/components/pages/SignUp.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Создать
+
+ Или
+ войти в свой аккаунт
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/components/support/ChangeRecordManager.vue b/front/src/components/support/ChangeRecordManager.vue
new file mode 100644
index 0000000..c0431f3
--- /dev/null
+++ b/front/src/components/support/ChangeRecordManager.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ group.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ Сохранить
+
+
+
+
+
diff --git a/front/src/components/support/PlanManager.vue b/front/src/components/support/PlanManager.vue
new file mode 100644
index 0000000..40578b9
--- /dev/null
+++ b/front/src/components/support/PlanManager.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Добавить
+
+
+
+
+
diff --git a/front/src/components/support/SpendingGroupManager.vue b/front/src/components/support/SpendingGroupManager.vue
new file mode 100644
index 0000000..c77aaff
--- /dev/null
+++ b/front/src/components/support/SpendingGroupManager.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+ Сохранить
+
+
+
+
+
\ No newline at end of file
diff --git a/front/src/core/api/Api.ts b/front/src/core/api/Api.ts
new file mode 100644
index 0000000..6e6cab0
--- /dev/null
+++ b/front/src/core/api/Api.ts
@@ -0,0 +1,470 @@
+/* eslint-disable */
+/* tslint:disable */
+/*
+ * ---------------------------------------------------------------
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
+ * ## ##
+ * ## AUTHOR: acacode ##
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
+ * ---------------------------------------------------------------
+ */
+
+import {
+ ChangeRecordDto,
+ ChangeRecordViewModel,
+ SpendingGroupDto,
+ SpendingGroupViewModel,
+ SpendingPlanDto,
+ SpendingPlanViewModel,
+ UserDto,
+ UserLoginDto,
+ UserViewModel,
+} from "./data-contracts";
+import { ContentType, HttpClient, RequestParams } from "./http-client";
+
+export class Api extends HttpClient {
+ /**
+ * No description
+ *
+ * @tags Auth
+ * @name AuthCreate
+ * @request POST:/api/Auth
+ * @response `200` `UserViewModel` Success
+ */
+ auth = (data: UserLoginDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/Auth`,
+ method: "POST",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags Auth
+ * @name AuthRegisterCreate
+ * @request POST:/api/Auth/register
+ * @response `200` `UserViewModel` Success
+ */
+ authRegister = (data: UserDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/Auth/register`,
+ method: "POST",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags ChangeRecord
+ * @name ChangeRecordCreate
+ * @request POST:/api/ChangeRecord
+ * @response `200` `ChangeRecordViewModel` Success
+ */
+ changeRecordCreate = (data: ChangeRecordDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/ChangeRecord`,
+ method: "POST",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags ChangeRecord
+ * @name ChangeRecordList
+ * @request GET:/api/ChangeRecord
+ * @response `200` `(ChangeRecordViewModel)[]` Success
+ */
+ changeRecordList = (params: RequestParams = {}) =>
+ this.request({
+ path: `/api/ChangeRecord`,
+ method: "GET",
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags ChangeRecord
+ * @name ChangeRecordPartialUpdate
+ * @request PATCH:/api/ChangeRecord
+ * @response `200` `ChangeRecordViewModel` Success
+ */
+ changeRecordPartialUpdate = (data: ChangeRecordDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/ChangeRecord`,
+ method: "PATCH",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags ChangeRecord
+ * @name ChangeRecordDelete
+ * @request DELETE:/api/ChangeRecord
+ * @response `200` `void` Success
+ */
+ changeRecordDelete = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ /** @format uuid */
+ SpendingGroupId?: string;
+ /** @format date-time */
+ From?: string;
+ /** @format date-time */
+ To?: string;
+ /** @format uuid */
+ UserId?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/ChangeRecord`,
+ method: "DELETE",
+ query: query,
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags ChangeRecord
+ * @name ChangeRecordFilterList
+ * @request GET:/api/ChangeRecord/filter
+ * @response `200` `(ChangeRecordViewModel)[]` Success
+ */
+ changeRecordFilterList = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ /** @format uuid */
+ SpendingGroupId?: string;
+ /** @format date-time */
+ From?: string;
+ /** @format date-time */
+ To?: string;
+ /** @format uuid */
+ UserId?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/ChangeRecord/filter`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupDetail
+ * @request GET:/api/SpendingGroup/{id}
+ * @response `200` `SpendingGroupViewModel` Success
+ */
+ spendingGroupDetail = (
+ id: string,
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ Name?: string;
+ /** @format uuid */
+ UserId?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingGroup/${id}`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupList
+ * @request GET:/api/SpendingGroup
+ * @response `200` `(SpendingGroupViewModel)[]` Success
+ */
+ spendingGroupList = (params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingGroup`,
+ method: "GET",
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupCreate
+ * @request POST:/api/SpendingGroup
+ * @response `200` `SpendingGroupViewModel` Success
+ */
+ spendingGroupCreate = (data: SpendingGroupDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingGroup`,
+ method: "POST",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupPartialUpdate
+ * @request PATCH:/api/SpendingGroup
+ * @response `200` `SpendingGroupViewModel` Success
+ */
+ spendingGroupPartialUpdate = (data: SpendingGroupDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingGroup`,
+ method: "PATCH",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupDelete
+ * @request DELETE:/api/SpendingGroup
+ * @response `200` `void` Success
+ */
+ spendingGroupDelete = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ Name?: string;
+ /** @format uuid */
+ UserId?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingGroup`,
+ method: "DELETE",
+ query: query,
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingGroup
+ * @name SpendingGroupFilterList
+ * @request GET:/api/SpendingGroup/filter
+ * @response `200` `(SpendingGroupViewModel)[]` Success
+ */
+ spendingGroupFilterList = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ Name?: string;
+ /** @format uuid */
+ UserId?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingGroup/filter`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanDetail
+ * @request GET:/api/SpendingPlan/{id}
+ * @response `200` `SpendingPlanViewModel` Success
+ */
+ spendingPlanDetail = (
+ id: string,
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingPlan/${id}`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanList
+ * @request GET:/api/SpendingPlan
+ * @response `200` `(SpendingPlanViewModel)[]` Success
+ */
+ spendingPlanList = (params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingPlan`,
+ method: "GET",
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanCreate
+ * @request POST:/api/SpendingPlan
+ * @response `200` `SpendingPlanViewModel` Success
+ */
+ spendingPlanCreate = (data: SpendingPlanDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingPlan`,
+ method: "POST",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanPartialUpdate
+ * @request PATCH:/api/SpendingPlan
+ * @response `200` `SpendingPlanViewModel` Success
+ */
+ spendingPlanPartialUpdate = (data: SpendingPlanDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/SpendingPlan`,
+ method: "PATCH",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanDelete
+ * @request DELETE:/api/SpendingPlan
+ * @response `200` `void` Success
+ */
+ spendingPlanDelete = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingPlan`,
+ method: "DELETE",
+ query: query,
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags SpendingPlan
+ * @name SpendingPlanFilterList
+ * @request GET:/api/SpendingPlan/filter
+ * @response `200` `(SpendingPlanViewModel)[]` Success
+ */
+ spendingPlanFilterList = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/SpendingPlan/filter`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags User
+ * @name UserList
+ * @request GET:/api/User
+ * @response `200` `UserViewModel` Success
+ */
+ userGet = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ Name?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/User`,
+ method: "GET",
+ query: query,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags User
+ * @name UserPartialUpdate
+ * @request PATCH:/api/User
+ * @response `200` `UserViewModel` Success
+ */
+ userPartialUpdate = (data: UserDto, params: RequestParams = {}) =>
+ this.request({
+ path: `/api/User`,
+ method: "PATCH",
+ body: data,
+ type: ContentType.Json,
+ format: "json",
+ ...params,
+ });
+ /**
+ * No description
+ *
+ * @tags User
+ * @name UserDelete
+ * @request DELETE:/api/User
+ * @response `200` `UserViewModel` Success
+ */
+ userDelete = (
+ query?: {
+ /** @format uuid */
+ Id?: string;
+ Name?: string;
+ },
+ params: RequestParams = {},
+ ) =>
+ this.request({
+ path: `/api/User`,
+ method: "DELETE",
+ query: query,
+ format: "json",
+ ...params,
+ });
+}
diff --git a/front/src/core/api/data-contracts.ts b/front/src/core/api/data-contracts.ts
new file mode 100644
index 0000000..7755fd0
--- /dev/null
+++ b/front/src/core/api/data-contracts.ts
@@ -0,0 +1,98 @@
+/* eslint-disable */
+/* tslint:disable */
+/*
+ * ---------------------------------------------------------------
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
+ * ## ##
+ * ## AUTHOR: acacode ##
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
+ * ---------------------------------------------------------------
+ */
+
+export interface ChangeRecordDto {
+ /** @format uuid */
+ id?: string;
+ /** @format uuid */
+ userId?: string;
+ /** @format uuid */
+ spendingGroupId?: string | null;
+ spendingGroupName?: string | null;
+ /** @format double */
+ sum?: number;
+ /** @format date-time */
+ changedAt?: string;
+}
+
+export interface ChangeRecordViewModel {
+ /** @format uuid */
+ id?: string;
+ /** @format double */
+ sum?: number;
+ /** @format date-time */
+ changedAt?: string;
+ spendingGroupName?: string | null;
+}
+
+export interface SpendingGroupDto {
+ /** @format uuid */
+ id?: string;
+ name?: string | null;
+ /** @format uuid */
+ userId?: string;
+ changeRecords?: ChangeRecordDto[] | null;
+ spendingPlans?: SpendingPlanDto[] | null;
+}
+
+export interface SpendingGroupViewModel {
+ /** @format uuid */
+ id?: string;
+ name?: string | null;
+ changeRecords?: ChangeRecordViewModel[] | null;
+ spendingPlans?: SpendingPlanViewModel[] | null;
+}
+
+export interface SpendingPlanDto {
+ /** @format uuid */
+ id?: string;
+ /** @format uuid */
+ spendingGroupId?: string;
+ /** @format double */
+ sum?: number;
+ /** @format date-time */
+ startAt?: string;
+ /** @format date-time */
+ endAt?: string;
+}
+
+export interface SpendingPlanViewModel {
+ /** @format uuid */
+ id?: string;
+ /** @format date-time */
+ startAt?: string;
+ /** @format date-time */
+ endAt?: string;
+ /** @format double */
+ sum?: number;
+}
+
+export interface UserDto {
+ /** @format uuid */
+ id?: string;
+ name?: string | null;
+ password?: string | null;
+ /** @format double */
+ balance?: number;
+}
+
+export interface UserLoginDto {
+ name?: string | null;
+ password?: string | null;
+}
+
+export interface UserViewModel {
+ /** @format uuid */
+ id?: string;
+ name?: string | null;
+ /** @format double */
+ balance?: number;
+}
diff --git a/front/src/core/api/http-client.ts b/front/src/core/api/http-client.ts
new file mode 100644
index 0000000..5140e54
--- /dev/null
+++ b/front/src/core/api/http-client.ts
@@ -0,0 +1,220 @@
+/* eslint-disable */
+/* tslint:disable */
+/*
+ * ---------------------------------------------------------------
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
+ * ## ##
+ * ## AUTHOR: acacode ##
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
+ * ---------------------------------------------------------------
+ */
+
+export type QueryParamsType = Record;
+export type ResponseFormat = keyof Omit;
+
+export interface FullRequestParams extends Omit {
+ /** set parameter to `true` for call `securityWorker` for this request */
+ secure?: boolean;
+ /** request path */
+ path: string;
+ /** content type of request body */
+ type?: ContentType;
+ /** query params */
+ query?: QueryParamsType;
+ /** format of response (i.e. response.json() -> format: "json") */
+ format?: ResponseFormat;
+ /** request body */
+ body?: unknown;
+ /** base url */
+ baseUrl?: string;
+ /** request cancellation token */
+ cancelToken?: CancelToken;
+}
+
+export type RequestParams = Omit;
+
+export interface ApiConfig {
+ baseUrl?: string;
+ baseApiParams?: Omit;
+ securityWorker?: (securityData: SecurityDataType | null) => Promise | RequestParams | void;
+ customFetch?: typeof fetch;
+}
+
+export interface HttpResponse extends Response {
+ data: D;
+ error: E;
+}
+
+type CancelToken = Symbol | string | number;
+
+export enum ContentType {
+ Json = "application/json",
+ FormData = "multipart/form-data",
+ UrlEncoded = "application/x-www-form-urlencoded",
+ Text = "text/plain",
+}
+
+export class HttpClient