From cd700dc758abacf961a922bfaffbf8ef55b80d8b Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Mon, 18 May 2026 22:22:09 -0400 Subject: [PATCH] feat(data): rename *.Services projects, lift TrackEntity onto BlazorBlocks data layer, regenerate initial Postgres migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeepDrftWeb.Services → DeepDrftData; DeepDrftContent.Services → DeepDrftContent.Data. TrackEntity:BaseEntity, TrackRepository:Repository<>, TrackManager:Manager<>+ITrackService. Drops DeepDrftModels PagingParameters/PagedResult in favour of Models.Common.* from BlazorBlocks. InitialCreate migration captures full schema including is_deleted index. --- CLI.sln | 4 +- DeepDrftCli/DeepDrftCli.csproj | 4 +- DeepDrftCli/Program.cs | 19 ++- DeepDrftCli/Services/CliService.cs | 10 +- DeepDrftCli/Services/GuiService.cs | 8 +- DeepDrftCms/DeepDrftCms.csproj | 2 +- DeepDrftCms/Pages/Tracks/TrackEdit.razor | 2 +- DeepDrftCms/Pages/Tracks/TrackList.razor | 2 +- DeepDrftCms/_Imports.razor | 3 +- .../Audio/WavOffsetService.cs | 2 +- .../CLAUDE.md | 0 .../Constants/VaultConstants.cs | 2 +- .../DeepDrftContent.Data.csproj | 0 .../Abstractions/IIndexFactory.cs | 6 +- .../Abstractions/IMediaTypeRegistry.cs | 6 +- .../FileDatabase/Models/IIndex.cs | 2 +- .../FileDatabase/Models/IndexData.cs | 4 +- .../FileDatabase/Models/MediaFactories.cs | 6 +- .../FileDatabase/Models/MediaModels.cs | 2 +- .../FileDatabase/Models/MediaVaultType.cs | 2 +- .../FileDatabase/Models/MetaData.cs | 2 +- .../FileDatabase/README.md | 0 .../FileDatabase/Services/FileDatabase.cs | 6 +- .../Services/IndexFactoryService.cs | 10 +- .../FileDatabase/Services/IndexSystem.cs | 8 +- .../FileDatabase/Services/IndexWatcher.cs | 4 +- .../FileDatabase/Services/MediaVault.cs | 6 +- .../Services/MediaVaultFactory.cs | 4 +- .../Services/SimpleMediaTypeRegistry.cs | 6 +- .../FileDatabase/Utils/FileUtils.cs | 4 +- .../FileDatabase/Utils/StructuralMap.cs | 2 +- .../FileDatabase/Utils/StructuralSet.cs | 2 +- .../Processors/AudioProcessor.cs | 4 +- .../TrackService.cs | 18 +-- .../Controllers/TrackController.cs | 18 +-- DeepDrftContent/DeepDrftContent.csproj | 2 +- DeepDrftContent/Program.cs | 2 +- DeepDrftContent/Startup.cs | 12 +- .../CLAUDE.md | 0 .../Data/Configurations/TrackConfiguration.cs | 61 ++++++++ .../Data/DeepDrftContext.cs | 8 +- .../Data/DeepDrftContextFactory.cs | 4 +- .../DeepDrftData.csproj | 2 + .../ITrackService.cs | 4 +- .../20260519021400_InitialCreate.Designer.cs | 25 +++- .../20260519021400_InitialCreate.cs | 15 +- .../DeepDrftContextModelSnapshot.cs | 21 ++- DeepDrftData/Repositories/TrackRepository.cs | 31 ++++ DeepDrftData/TrackConverter.cs | 44 ++++++ DeepDrftData/TrackManager.cs | 137 ++++++++++++++++++ DeepDrftHome.sln | 4 +- DeepDrftModels/DTOs/TrackDto.cs | 22 ++- DeepDrftModels/DeepDrftModels.csproj | 3 +- DeepDrftModels/Entities/TrackEntity.cs | 12 +- DeepDrftModels/Models/PagedResult.cs | 35 ----- DeepDrftModels/Models/PagingParameters.cs | 25 ---- DeepDrftTests/DeepDrftTests.csproj | 2 +- DeepDrftTests/FileDatabaseTests.cs | 4 +- DeepDrftTests/IndexSystemTests.cs | 8 +- DeepDrftTests/MediaVaultFactoryTests.cs | 4 +- DeepDrftTests/MediaVaultTests.cs | 6 +- DeepDrftTests/ModelTests.cs | 2 +- DeepDrftTests/SimpleMediaTypeRegistryTests.cs | 4 +- DeepDrftTests/TestData.cs | 2 +- DeepDrftTests/UtilityTests.cs | 4 +- DeepDrftWeb.Client/Clients/TrackClient.cs | 2 +- DeepDrftWeb.Client/Pages/TracksView.razor.cs | 2 +- .../ViewModels/TracksViewModel.cs | 2 +- .../Data/Configurations/TrackConfiguration.cs | 52 ------- .../20260518025102_Initial.Designer.cs | 81 ----------- .../20260518035137_AddCreatedByUserId.cs | 28 ---- .../Repositories/TrackRepository.cs | 84 ----------- DeepDrftWeb.Services/TrackService.cs | 125 ---------------- .../Controllers/CmsDeleteController.cs | 2 +- DeepDrftWeb/Controllers/CmsEditController.cs | 2 +- .../Controllers/CmsUploadController.cs | 4 +- DeepDrftWeb/Controllers/TrackController.cs | 6 +- DeepDrftWeb/DeepDrftWeb.csproj | 2 +- DeepDrftWeb/Startup.cs | 29 ++-- NuGet.Config | 1 + WebAPI.sln | 2 +- WebUI.sln | 2 +- 82 files changed, 511 insertions(+), 600 deletions(-) rename {DeepDrftContent.Services => DeepDrftContent.Data}/Audio/WavOffsetService.cs (99%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/CLAUDE.md (100%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/Constants/VaultConstants.cs (83%) rename DeepDrftContent.Services/DeepDrftContent.Services.csproj => DeepDrftContent.Data/DeepDrftContent.Data.csproj (100%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Abstractions/IIndexFactory.cs (88%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Abstractions/IMediaTypeRegistry.cs (93%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/IIndex.cs (96%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/IndexData.cs (97%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/MediaFactories.cs (96%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/MediaModels.cs (99%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/MediaVaultType.cs (72%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Models/MetaData.cs (96%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/README.md (100%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/FileDatabase.cs (97%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/IndexFactoryService.cs (93%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/IndexSystem.cs (96%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/IndexWatcher.cs (97%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/MediaVault.cs (98%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/MediaVaultFactory.cs (81%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Services/SimpleMediaTypeRegistry.cs (98%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Utils/FileUtils.cs (97%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Utils/StructuralMap.cs (98%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/FileDatabase/Utils/StructuralSet.cs (98%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/Processors/AudioProcessor.cs (98%) rename {DeepDrftContent.Services => DeepDrftContent.Data}/TrackService.cs (87%) rename {DeepDrftWeb.Services => DeepDrftData}/CLAUDE.md (100%) create mode 100644 DeepDrftData/Data/Configurations/TrackConfiguration.cs rename {DeepDrftWeb.Services => DeepDrftData}/Data/DeepDrftContext.cs (82%) rename {DeepDrftWeb.Services => DeepDrftData}/Data/DeepDrftContextFactory.cs (96%) rename DeepDrftWeb.Services/DeepDrftWeb.Services.csproj => DeepDrftData/DeepDrftData.csproj (86%) rename {DeepDrftWeb.Services => DeepDrftData}/ITrackService.cs (90%) rename DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.Designer.cs => DeepDrftData/Migrations/20260519021400_InitialCreate.Designer.cs (77%) rename DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs => DeepDrftData/Migrations/20260519021400_InitialCreate.cs (70%) rename {DeepDrftWeb.Services => DeepDrftData}/Migrations/DeepDrftContextModelSnapshot.cs (79%) create mode 100644 DeepDrftData/Repositories/TrackRepository.cs create mode 100644 DeepDrftData/TrackConverter.cs create mode 100644 DeepDrftData/TrackManager.cs delete mode 100644 DeepDrftModels/Models/PagedResult.cs delete mode 100644 DeepDrftModels/Models/PagingParameters.cs delete mode 100644 DeepDrftWeb.Services/Data/Configurations/TrackConfiguration.cs delete mode 100644 DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs delete mode 100644 DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.cs delete mode 100644 DeepDrftWeb.Services/Repositories/TrackRepository.cs delete mode 100644 DeepDrftWeb.Services/TrackService.cs diff --git a/CLI.sln b/CLI.sln index 182fd88..0e074c4 100644 --- a/CLI.sln +++ b/CLI.sln @@ -2,9 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftCli", "DeepDrftCli\DeepDrftCli.csproj", "{84844B37-FD15-4AFC-850B-DD432AA33B4C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Services", "DeepDrftContent.Services\DeepDrftContent.Services.csproj", "{169D5D3E-DAEC-46BE-98EE-CC5EBF5E3E8A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Data", "DeepDrftContent.Data\DeepDrftContent.Data.csproj", "{169D5D3E-DAEC-46BE-98EE-CC5EBF5E3E8A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftWeb.Services", "DeepDrftWeb.Services\DeepDrftWeb.Services.csproj", "{A3DA341B-589E-4705-AB66-6B22652A9B36}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftData", "DeepDrftData\DeepDrftData.csproj", "{A3DA341B-589E-4705-AB66-6B22652A9B36}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetBlocks", "C:\lib\NetBlocks\NetBlocks.csproj", "{41FC69D0-F60D-41B4-AA41-C2382C83DFE8}" EndProject diff --git a/DeepDrftCli/DeepDrftCli.csproj b/DeepDrftCli/DeepDrftCli.csproj index 6846a07..9a5a905 100644 --- a/DeepDrftCli/DeepDrftCli.csproj +++ b/DeepDrftCli/DeepDrftCli.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/DeepDrftCli/Program.cs b/DeepDrftCli/Program.cs index 1f086c4..244fa1c 100644 --- a/DeepDrftCli/Program.cs +++ b/DeepDrftCli/Program.cs @@ -3,10 +3,11 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Configuration; using Microsoft.EntityFrameworkCore; -using DeepDrftWeb.Services.Data; -using DeepDrftWeb.Services.Repositories; -using DeepDrftContent.Services.FileDatabase.Services; -using DeepDrftContent.Services.Processors; +using DeepDrftData; +using DeepDrftData.Data; +using DeepDrftData.Repositories; +using DeepDrftContent.Data.FileDatabase.Services; +using DeepDrftContent.Data.Processors; using DeepDrftCli.Services; using DeepDrftCli.Models; using NetBlocks.Utilities.Environment; @@ -49,11 +50,13 @@ builder.Services.AddSingleton(provider => } }); -// Add services +// Add services. TrackManager fronts the BlazorBlocks data layer and implements +// ITrackService for legacy consumers; same scoped instance backs both registrations. builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(sp => sp.GetRequiredService()); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -72,4 +75,4 @@ else // Run traditional CLI mode var cliService = app.Services.GetRequiredService(); await cliService.RunAsync(args); -} \ No newline at end of file +} diff --git a/DeepDrftCli/Services/CliService.cs b/DeepDrftCli/Services/CliService.cs index ae26961..d509eca 100644 --- a/DeepDrftCli/Services/CliService.cs +++ b/DeepDrftCli/Services/CliService.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; -using DeepDrftContent.Services; +using DeepDrftContent.Data; using DeepDrftModels.Entities; using NetBlocks.Models; using DeepDrftCli.Utils; @@ -13,13 +13,13 @@ namespace DeepDrftCli.Services; public class CliService { private readonly ILogger _logger; - private readonly DeepDrftWeb.Services.ITrackService _webTrackService; - private readonly DeepDrftContent.Services.TrackService _contentTrackService; + private readonly DeepDrftData.ITrackService _webTrackService; + private readonly DeepDrftContent.Data.TrackService _contentTrackService; public CliService( ILogger logger, - DeepDrftWeb.Services.ITrackService webTrackService, - DeepDrftContent.Services.TrackService contentTrackService) + DeepDrftData.ITrackService webTrackService, + DeepDrftContent.Data.TrackService contentTrackService) { _logger = logger; _webTrackService = webTrackService; diff --git a/DeepDrftCli/Services/GuiService.cs b/DeepDrftCli/Services/GuiService.cs index 762a094..6af8972 100644 --- a/DeepDrftCli/Services/GuiService.cs +++ b/DeepDrftCli/Services/GuiService.cs @@ -11,8 +11,8 @@ namespace DeepDrftCli.Services; public class GuiService { private readonly ILogger _logger; - private readonly DeepDrftWeb.Services.ITrackService _webTrackService; - private readonly DeepDrftContent.Services.TrackService _contentTrackService; + private readonly DeepDrftData.ITrackService _webTrackService; + private readonly DeepDrftContent.Data.TrackService _contentTrackService; // GUI Components private Window? _mainWindow; @@ -24,8 +24,8 @@ public class GuiService public GuiService( ILogger logger, - DeepDrftWeb.Services.ITrackService webTrackService, - DeepDrftContent.Services.TrackService contentTrackService) + DeepDrftData.ITrackService webTrackService, + DeepDrftContent.Data.TrackService contentTrackService) { _logger = logger; _webTrackService = webTrackService; diff --git a/DeepDrftCms/DeepDrftCms.csproj b/DeepDrftCms/DeepDrftCms.csproj index c484fdc..66c85e7 100644 --- a/DeepDrftCms/DeepDrftCms.csproj +++ b/DeepDrftCms/DeepDrftCms.csproj @@ -21,7 +21,7 @@ - + diff --git a/DeepDrftCms/Pages/Tracks/TrackEdit.razor b/DeepDrftCms/Pages/Tracks/TrackEdit.razor index 72344cc..5de4bfa 100644 --- a/DeepDrftCms/Pages/Tracks/TrackEdit.razor +++ b/DeepDrftCms/Pages/Tracks/TrackEdit.razor @@ -3,7 +3,7 @@ @rendermode InteractiveServer @using AuthBlocksWeb.HierarchicalAuthorize @using AuthBlocksWeb.Services -@using DeepDrftWeb.Services +@using DeepDrftData @using System.Net.Http.Headers @using System.Net.Http.Json @attribute [HierarchicalRoleAuthorize("Admin")] diff --git a/DeepDrftCms/Pages/Tracks/TrackList.razor b/DeepDrftCms/Pages/Tracks/TrackList.razor index a7f66d4..cedd5f9 100644 --- a/DeepDrftCms/Pages/Tracks/TrackList.razor +++ b/DeepDrftCms/Pages/Tracks/TrackList.razor @@ -3,7 +3,7 @@ @using System.Net @using System.Net.Http.Headers @using AuthBlocksWeb.HierarchicalAuthorize -@using DeepDrftModels.Models +@using Models.Common @attribute [HierarchicalRoleAuthorize("Admin")] @inject ITrackService TrackService @inject IHttpClientFactory HttpClientFactory diff --git a/DeepDrftCms/_Imports.razor b/DeepDrftCms/_Imports.razor index edc98a0..b0fbed9 100644 --- a/DeepDrftCms/_Imports.razor +++ b/DeepDrftCms/_Imports.razor @@ -9,5 +9,6 @@ @using Microsoft.JSInterop @using DeepDrftCms @using DeepDrftModels.Entities -@using DeepDrftWeb.Services +@using DeepDrftData +@using Models.Common @using MudBlazor diff --git a/DeepDrftContent.Services/Audio/WavOffsetService.cs b/DeepDrftContent.Data/Audio/WavOffsetService.cs similarity index 99% rename from DeepDrftContent.Services/Audio/WavOffsetService.cs rename to DeepDrftContent.Data/Audio/WavOffsetService.cs index e40a59b..602e48a 100644 --- a/DeepDrftContent.Services/Audio/WavOffsetService.cs +++ b/DeepDrftContent.Data/Audio/WavOffsetService.cs @@ -1,6 +1,6 @@ using System.Text; -namespace DeepDrftContent.Services.Audio; +namespace DeepDrftContent.Data.Audio; /// /// Service for creating WAV audio streams starting from a byte offset. diff --git a/DeepDrftContent.Services/CLAUDE.md b/DeepDrftContent.Data/CLAUDE.md similarity index 100% rename from DeepDrftContent.Services/CLAUDE.md rename to DeepDrftContent.Data/CLAUDE.md diff --git a/DeepDrftContent.Services/Constants/VaultConstants.cs b/DeepDrftContent.Data/Constants/VaultConstants.cs similarity index 83% rename from DeepDrftContent.Services/Constants/VaultConstants.cs rename to DeepDrftContent.Data/Constants/VaultConstants.cs index 83a6daf..12d703f 100644 --- a/DeepDrftContent.Services/Constants/VaultConstants.cs +++ b/DeepDrftContent.Data/Constants/VaultConstants.cs @@ -1,4 +1,4 @@ -namespace DeepDrftContent.Services.Constants; +namespace DeepDrftContent.Data.Constants; /// /// Constants for FileDatabase vault names diff --git a/DeepDrftContent.Services/DeepDrftContent.Services.csproj b/DeepDrftContent.Data/DeepDrftContent.Data.csproj similarity index 100% rename from DeepDrftContent.Services/DeepDrftContent.Services.csproj rename to DeepDrftContent.Data/DeepDrftContent.Data.csproj diff --git a/DeepDrftContent.Services/FileDatabase/Abstractions/IIndexFactory.cs b/DeepDrftContent.Data/FileDatabase/Abstractions/IIndexFactory.cs similarity index 88% rename from DeepDrftContent.Services/FileDatabase/Abstractions/IIndexFactory.cs rename to DeepDrftContent.Data/FileDatabase/Abstractions/IIndexFactory.cs index 8dc59a2..3a63052 100644 --- a/DeepDrftContent.Services/FileDatabase/Abstractions/IIndexFactory.cs +++ b/DeepDrftContent.Data/FileDatabase/Abstractions/IIndexFactory.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using IndexType = DeepDrftContent.Services.FileDatabase.Services.IndexType; +using DeepDrftContent.Data.FileDatabase.Models; +using IndexType = DeepDrftContent.Data.FileDatabase.Services.IndexType; -namespace DeepDrftContent.Services.FileDatabase.Abstractions; +namespace DeepDrftContent.Data.FileDatabase.Abstractions; /// /// Interface for creating index instances diff --git a/DeepDrftContent.Services/FileDatabase/Abstractions/IMediaTypeRegistry.cs b/DeepDrftContent.Data/FileDatabase/Abstractions/IMediaTypeRegistry.cs similarity index 93% rename from DeepDrftContent.Services/FileDatabase/Abstractions/IMediaTypeRegistry.cs rename to DeepDrftContent.Data/FileDatabase/Abstractions/IMediaTypeRegistry.cs index f7803bc..5dffb2c 100644 --- a/DeepDrftContent.Services/FileDatabase/Abstractions/IMediaTypeRegistry.cs +++ b/DeepDrftContent.Data/FileDatabase/Abstractions/IMediaTypeRegistry.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; -namespace DeepDrftContent.Services.FileDatabase.Abstractions; +namespace DeepDrftContent.Data.FileDatabase.Abstractions; /// /// Interface for registering media type factories diff --git a/DeepDrftContent.Services/FileDatabase/Models/IIndex.cs b/DeepDrftContent.Data/FileDatabase/Models/IIndex.cs similarity index 96% rename from DeepDrftContent.Services/FileDatabase/Models/IIndex.cs rename to DeepDrftContent.Data/FileDatabase/Models/IIndex.cs index c8df40e..f375e65 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/IIndex.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/IIndex.cs @@ -1,4 +1,4 @@ -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Base interface for all index types - minimal contract diff --git a/DeepDrftContent.Services/FileDatabase/Models/IndexData.cs b/DeepDrftContent.Data/FileDatabase/Models/IndexData.cs similarity index 97% rename from DeepDrftContent.Services/FileDatabase/Models/IndexData.cs rename to DeepDrftContent.Data/FileDatabase/Models/IndexData.cs index 92acb48..794945c 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/IndexData.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/IndexData.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Utils; using System.Text.Json.Serialization; -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Base class for index data used in serialization diff --git a/DeepDrftContent.Services/FileDatabase/Models/MediaFactories.cs b/DeepDrftContent.Data/FileDatabase/Models/MediaFactories.cs similarity index 96% rename from DeepDrftContent.Services/FileDatabase/Models/MediaFactories.cs rename to DeepDrftContent.Data/FileDatabase/Models/MediaFactories.cs index 80be94a..9ebd177 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/MediaFactories.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/MediaFactories.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Abstractions; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Abstractions; +using DeepDrftContent.Data.FileDatabase.Services; -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Shared media type registry instance — one allocation for all factory classes in this file. diff --git a/DeepDrftContent.Services/FileDatabase/Models/MediaModels.cs b/DeepDrftContent.Data/FileDatabase/Models/MediaModels.cs similarity index 99% rename from DeepDrftContent.Services/FileDatabase/Models/MediaModels.cs rename to DeepDrftContent.Data/FileDatabase/Models/MediaModels.cs index 862fac9..a62d5e5 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/MediaModels.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/MediaModels.cs @@ -1,4 +1,4 @@ -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Parameters for creating a FileBinary diff --git a/DeepDrftContent.Services/FileDatabase/Models/MediaVaultType.cs b/DeepDrftContent.Data/FileDatabase/Models/MediaVaultType.cs similarity index 72% rename from DeepDrftContent.Services/FileDatabase/Models/MediaVaultType.cs rename to DeepDrftContent.Data/FileDatabase/Models/MediaVaultType.cs index ba60bd9..bd52ec4 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/MediaVaultType.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/MediaVaultType.cs @@ -1,4 +1,4 @@ -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Enum representing different types of media vaults diff --git a/DeepDrftContent.Services/FileDatabase/Models/MetaData.cs b/DeepDrftContent.Data/FileDatabase/Models/MetaData.cs similarity index 96% rename from DeepDrftContent.Services/FileDatabase/Models/MetaData.cs rename to DeepDrftContent.Data/FileDatabase/Models/MetaData.cs index ac9a837..014918c 100644 --- a/DeepDrftContent.Services/FileDatabase/Models/MetaData.cs +++ b/DeepDrftContent.Data/FileDatabase/Models/MetaData.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace DeepDrftContent.Services.FileDatabase.Models; +namespace DeepDrftContent.Data.FileDatabase.Models; /// /// Base metadata for media entries diff --git a/DeepDrftContent.Services/FileDatabase/README.md b/DeepDrftContent.Data/FileDatabase/README.md similarity index 100% rename from DeepDrftContent.Services/FileDatabase/README.md rename to DeepDrftContent.Data/FileDatabase/README.md diff --git a/DeepDrftContent.Services/FileDatabase/Services/FileDatabase.cs b/DeepDrftContent.Data/FileDatabase/Services/FileDatabase.cs similarity index 97% rename from DeepDrftContent.Services/FileDatabase/Services/FileDatabase.cs rename to DeepDrftContent.Data/FileDatabase/Services/FileDatabase.cs index a3b2893..410700e 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/FileDatabase.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/FileDatabase.cs @@ -1,8 +1,8 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Utils; using Microsoft.Extensions.Logging; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Main file database class that orchestrates multiple media vaults. diff --git a/DeepDrftContent.Services/FileDatabase/Services/IndexFactoryService.cs b/DeepDrftContent.Data/FileDatabase/Services/IndexFactoryService.cs similarity index 93% rename from DeepDrftContent.Services/FileDatabase/Services/IndexFactoryService.cs rename to DeepDrftContent.Data/FileDatabase/Services/IndexFactoryService.cs index 9b88f1b..d8f1a4a 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/IndexFactoryService.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/IndexFactoryService.cs @@ -1,9 +1,9 @@ -using DeepDrftContent.Services.FileDatabase.Abstractions; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Utils; -using IndexType = DeepDrftContent.Services.FileDatabase.Services.IndexType; +using DeepDrftContent.Data.FileDatabase.Abstractions; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Utils; +using IndexType = DeepDrftContent.Data.FileDatabase.Services.IndexType; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Factory service for creating and managing indexes diff --git a/DeepDrftContent.Services/FileDatabase/Services/IndexSystem.cs b/DeepDrftContent.Data/FileDatabase/Services/IndexSystem.cs similarity index 96% rename from DeepDrftContent.Services/FileDatabase/Services/IndexSystem.cs rename to DeepDrftContent.Data/FileDatabase/Services/IndexSystem.cs index 96ba880..74e56a1 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/IndexSystem.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/IndexSystem.cs @@ -1,9 +1,9 @@ -using DeepDrftContent.Services.FileDatabase.Abstractions; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Abstractions; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Utils; using Microsoft.Extensions.Logging; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Enum representing different types of indexes diff --git a/DeepDrftContent.Services/FileDatabase/Services/IndexWatcher.cs b/DeepDrftContent.Data/FileDatabase/Services/IndexWatcher.cs similarity index 97% rename from DeepDrftContent.Services/FileDatabase/Services/IndexWatcher.cs rename to DeepDrftContent.Data/FileDatabase/Services/IndexWatcher.cs index 2c6e3ec..72e299b 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/IndexWatcher.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/IndexWatcher.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; using Microsoft.Extensions.Logging; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Watches index files for external modifications and triggers reloads. diff --git a/DeepDrftContent.Services/FileDatabase/Services/MediaVault.cs b/DeepDrftContent.Data/FileDatabase/Services/MediaVault.cs similarity index 98% rename from DeepDrftContent.Services/FileDatabase/Services/MediaVault.cs rename to DeepDrftContent.Data/FileDatabase/Services/MediaVault.cs index f6a4671..cd39fef 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/MediaVault.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/MediaVault.cs @@ -1,8 +1,8 @@ using System.Text.RegularExpressions; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Utils; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Abstract base class for media vaults that store and manage media files diff --git a/DeepDrftContent.Services/FileDatabase/Services/MediaVaultFactory.cs b/DeepDrftContent.Data/FileDatabase/Services/MediaVaultFactory.cs similarity index 81% rename from DeepDrftContent.Services/FileDatabase/Services/MediaVaultFactory.cs rename to DeepDrftContent.Data/FileDatabase/Services/MediaVaultFactory.cs index 54b0f04..b851e2f 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/MediaVaultFactory.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/MediaVaultFactory.cs @@ -1,6 +1,6 @@ -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Factory for creating media vaults diff --git a/DeepDrftContent.Services/FileDatabase/Services/SimpleMediaTypeRegistry.cs b/DeepDrftContent.Data/FileDatabase/Services/SimpleMediaTypeRegistry.cs similarity index 98% rename from DeepDrftContent.Services/FileDatabase/Services/SimpleMediaTypeRegistry.cs rename to DeepDrftContent.Data/FileDatabase/Services/SimpleMediaTypeRegistry.cs index 986cdfd..8af4c7a 100644 --- a/DeepDrftContent.Services/FileDatabase/Services/SimpleMediaTypeRegistry.cs +++ b/DeepDrftContent.Data/FileDatabase/Services/SimpleMediaTypeRegistry.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Abstractions; -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Abstractions; +using DeepDrftContent.Data.FileDatabase.Models; -namespace DeepDrftContent.Services.FileDatabase.Services; +namespace DeepDrftContent.Data.FileDatabase.Services; /// /// Simple dictionary-based registry for media type factories diff --git a/DeepDrftContent.Services/FileDatabase/Utils/FileUtils.cs b/DeepDrftContent.Data/FileDatabase/Utils/FileUtils.cs similarity index 97% rename from DeepDrftContent.Services/FileDatabase/Utils/FileUtils.cs rename to DeepDrftContent.Data/FileDatabase/Utils/FileUtils.cs index 637478a..02b6353 100644 --- a/DeepDrftContent.Services/FileDatabase/Utils/FileUtils.cs +++ b/DeepDrftContent.Data/FileDatabase/Utils/FileUtils.cs @@ -1,7 +1,7 @@ using System.Text.Json; -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; -namespace DeepDrftContent.Services.FileDatabase.Utils; +namespace DeepDrftContent.Data.FileDatabase.Utils; /// /// Utility class for file I/O operations, matching the TypeScript file utilities diff --git a/DeepDrftContent.Services/FileDatabase/Utils/StructuralMap.cs b/DeepDrftContent.Data/FileDatabase/Utils/StructuralMap.cs similarity index 98% rename from DeepDrftContent.Services/FileDatabase/Utils/StructuralMap.cs rename to DeepDrftContent.Data/FileDatabase/Utils/StructuralMap.cs index cde98b4..d6748cd 100644 --- a/DeepDrftContent.Services/FileDatabase/Utils/StructuralMap.cs +++ b/DeepDrftContent.Data/FileDatabase/Utils/StructuralMap.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Text.Json; -namespace DeepDrftContent.Services.FileDatabase.Utils; +namespace DeepDrftContent.Data.FileDatabase.Utils; /// /// A map implementation that uses structural equality for keys by serializing them to JSON. diff --git a/DeepDrftContent.Services/FileDatabase/Utils/StructuralSet.cs b/DeepDrftContent.Data/FileDatabase/Utils/StructuralSet.cs similarity index 98% rename from DeepDrftContent.Services/FileDatabase/Utils/StructuralSet.cs rename to DeepDrftContent.Data/FileDatabase/Utils/StructuralSet.cs index 6592c20..d7ecc0f 100644 --- a/DeepDrftContent.Services/FileDatabase/Utils/StructuralSet.cs +++ b/DeepDrftContent.Data/FileDatabase/Utils/StructuralSet.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Text.Json; -namespace DeepDrftContent.Services.FileDatabase.Utils; +namespace DeepDrftContent.Data.FileDatabase.Utils; /// /// A set implementation that uses structural equality for values by serializing them to JSON. diff --git a/DeepDrftContent.Services/Processors/AudioProcessor.cs b/DeepDrftContent.Data/Processors/AudioProcessor.cs similarity index 98% rename from DeepDrftContent.Services/Processors/AudioProcessor.cs rename to DeepDrftContent.Data/Processors/AudioProcessor.cs index ffac64a..2fc2dec 100644 --- a/DeepDrftContent.Services/Processors/AudioProcessor.cs +++ b/DeepDrftContent.Data/Processors/AudioProcessor.cs @@ -1,6 +1,6 @@ -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; -namespace DeepDrftContent.Services.Processors; +namespace DeepDrftContent.Data.Processors; /// /// Service for processing audio files and extracting metadata diff --git a/DeepDrftContent.Services/TrackService.cs b/DeepDrftContent.Data/TrackService.cs similarity index 87% rename from DeepDrftContent.Services/TrackService.cs rename to DeepDrftContent.Data/TrackService.cs index 1906031..1e752cd 100644 --- a/DeepDrftContent.Services/TrackService.cs +++ b/DeepDrftContent.Data/TrackService.cs @@ -1,9 +1,9 @@ -using DeepDrftContent.Services.Constants; -using DeepDrftContent.Services.FileDatabase.Services; -using DeepDrftContent.Services.Processors; +using DeepDrftContent.Data.Constants; +using DeepDrftContent.Data.FileDatabase.Services; +using DeepDrftContent.Data.Processors; using DeepDrftModels.Entities; -namespace DeepDrftContent.Services; +namespace DeepDrftContent.Data; /// /// Service for managing tracks in both SQL and FileDatabase @@ -52,7 +52,7 @@ public class TrackService // Ensure tracks vault exists if (!_fileDatabase.HasVault(VaultConstants.Tracks)) { - await _fileDatabase.CreateVaultAsync(VaultConstants.Tracks, DeepDrftContent.Services.FileDatabase.Models.MediaVaultType.Audio); + await _fileDatabase.CreateVaultAsync(VaultConstants.Tracks, DeepDrftContent.Data.FileDatabase.Models.MediaVaultType.Audio); } // Store the audio in FileDatabase @@ -87,9 +87,9 @@ public class TrackService /// /// Track ID (EntryKey) /// Audio binary or null if not found - public async Task GetAudioBinaryAsync(string trackId) + public async Task GetAudioBinaryAsync(string trackId) { - return await _fileDatabase.LoadResourceAsync(VaultConstants.Tracks, trackId); + return await _fileDatabase.LoadResourceAsync(VaultConstants.Tracks, trackId); } /// @@ -107,7 +107,7 @@ public class TrackService { if (!_fileDatabase.HasVault(VaultConstants.Tracks)) { - await _fileDatabase.CreateVaultAsync(VaultConstants.Tracks, DeepDrftContent.Services.FileDatabase.Models.MediaVaultType.Audio); + await _fileDatabase.CreateVaultAsync(VaultConstants.Tracks, DeepDrftContent.Data.FileDatabase.Models.MediaVaultType.Audio); } } -} \ No newline at end of file +} diff --git a/DeepDrftContent/Controllers/TrackController.cs b/DeepDrftContent/Controllers/TrackController.cs index af2fd8e..0cd7825 100644 --- a/DeepDrftContent/Controllers/TrackController.cs +++ b/DeepDrftContent/Controllers/TrackController.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.Audio; -using DeepDrftContent.Services.Constants; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.Audio; +using DeepDrftContent.Data.Constants; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; using DeepDrftContent.Middleware; using Microsoft.AspNetCore.Mvc; @@ -11,7 +11,7 @@ namespace DeepDrftContent.Controllers; [Route("api/[controller]")] public class TrackController : ControllerBase { - private readonly DeepDrftContent.Services.TrackService _trackService; + private readonly DeepDrftContent.Data.TrackService _trackService; private readonly WavOffsetService _wavOffsetService; private readonly ILogger _logger; @@ -19,11 +19,11 @@ public class TrackController : ControllerBase // AudioBinaryDto over the wire, not a WAV file path. TrackService.AddTrackFromWavAsync is // file-path-oriented and not applicable here. If a file-upload flow is added in future, // route it through TrackService instead. - private readonly DeepDrftContent.Services.FileDatabase.Services.FileDatabase _fileDatabase; + private readonly DeepDrftContent.Data.FileDatabase.Services.FileDatabase _fileDatabase; public TrackController( - DeepDrftContent.Services.TrackService trackService, - DeepDrftContent.Services.FileDatabase.Services.FileDatabase fileDatabase, + DeepDrftContent.Data.TrackService trackService, + DeepDrftContent.Data.FileDatabase.Services.FileDatabase fileDatabase, WavOffsetService wavOffsetService, ILogger logger) { @@ -245,7 +245,7 @@ public class TrackController : ControllerBase // Direct FileDatabase write: this endpoint receives an already-processed AudioBinaryDto, // not a WAV file, so TrackService.AddTrackFromWavAsync does not apply. See constructor comment. var success = await _fileDatabase.RegisterResourceAsync( - DeepDrftContent.Services.Constants.VaultConstants.Tracks, trackId, audioBinary); + DeepDrftContent.Data.Constants.VaultConstants.Tracks, trackId, audioBinary); return success ? Ok() : BadRequest("Failed to store audio track"); } diff --git a/DeepDrftContent/DeepDrftContent.csproj b/DeepDrftContent/DeepDrftContent.csproj index 732f465..d04b35e 100644 --- a/DeepDrftContent/DeepDrftContent.csproj +++ b/DeepDrftContent/DeepDrftContent.csproj @@ -12,7 +12,7 @@ - + diff --git a/DeepDrftContent/Program.cs b/DeepDrftContent/Program.cs index bd3aeff..91b3e0f 100644 --- a/DeepDrftContent/Program.cs +++ b/DeepDrftContent/Program.cs @@ -1,5 +1,5 @@ using DeepDrftContent; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Services; using DeepDrftContent.Middleware; using DeepDrftContent.Models; using Microsoft.AspNetCore.HttpOverrides; diff --git a/DeepDrftContent/Startup.cs b/DeepDrftContent/Startup.cs index 25d2a50..5c3c7f0 100644 --- a/DeepDrftContent/Startup.cs +++ b/DeepDrftContent/Startup.cs @@ -1,9 +1,9 @@ -using DeepDrftContent.Services; -using DeepDrftContent.Services.Audio; -using DeepDrftContent.Services.Constants; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; -using DeepDrftContent.Services.Processors; +using DeepDrftContent.Data; +using DeepDrftContent.Data.Audio; +using DeepDrftContent.Data.Constants; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; +using DeepDrftContent.Data.Processors; using DeepDrftContent.Models; using Microsoft.Extensions.Logging; using NetBlocks.Utilities.Environment; diff --git a/DeepDrftWeb.Services/CLAUDE.md b/DeepDrftData/CLAUDE.md similarity index 100% rename from DeepDrftWeb.Services/CLAUDE.md rename to DeepDrftData/CLAUDE.md diff --git a/DeepDrftData/Data/Configurations/TrackConfiguration.cs b/DeepDrftData/Data/Configurations/TrackConfiguration.cs new file mode 100644 index 0000000..9da506b --- /dev/null +++ b/DeepDrftData/Data/Configurations/TrackConfiguration.cs @@ -0,0 +1,61 @@ +using Data.Data.Configurations; +using DeepDrftModels.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace DeepDrftData.Data.Configurations; + +public class TrackConfiguration : BaseEntityConfiguration +{ + public override void Configure(EntityTypeBuilder builder) + { + // Wires up Id PK + audit columns (CreatedAt, UpdatedAt, IsDeleted) and the IsDeleted index. + base.Configure(builder); + + builder.ToTable("track"); + + // Map the base audit columns to the snake_case naming the rest of the schema uses. + builder.Property(e => e.Id).HasColumnName("id"); + builder.Property(e => e.CreatedAt).HasColumnName("created_at"); + builder.Property(e => e.UpdatedAt).HasColumnName("updated_at"); + builder.Property(e => e.IsDeleted).HasColumnName("is_deleted"); + + builder.Property(e => e.EntryKey) + .IsRequired() + .HasMaxLength(100) + .HasColumnName("entry_key"); + + builder.Property(e => e.TrackName) + .IsRequired() + .HasMaxLength(200) + .HasColumnName("track_name"); + + builder.Property(e => e.Artist) + .IsRequired() + .HasMaxLength(200) + .HasColumnName("artist"); + + builder.Property(e => e.Album) + .HasMaxLength(200) + .HasColumnName("album"); + + builder.Property(e => e.Genre) + .HasMaxLength(100) + .HasColumnName("genre"); + + builder.Property(e => e.ReleaseDate) + .HasColumnName("release_date"); + + builder.Property(e => e.ImagePath) + .HasMaxLength(500) + .HasColumnName("image_path"); + + builder.Property(e => e.CreatedByUserId) + .HasColumnName("created_by_user_id"); + + // Explicit index on is_deleted so soft-delete global query filters are + // not full table scans. base.Configure may or may not add this depending + // on the BlazorBlocks.Data version; declaring it here guarantees it. + builder.HasIndex(e => e.IsDeleted).HasDatabaseName("IX_track_is_deleted"); + } +} diff --git a/DeepDrftWeb.Services/Data/DeepDrftContext.cs b/DeepDrftData/Data/DeepDrftContext.cs similarity index 82% rename from DeepDrftWeb.Services/Data/DeepDrftContext.cs rename to DeepDrftData/Data/DeepDrftContext.cs index 77017cb..b0839dd 100644 --- a/DeepDrftWeb.Services/Data/DeepDrftContext.cs +++ b/DeepDrftData/Data/DeepDrftContext.cs @@ -1,8 +1,8 @@ using DeepDrftModels.Entities; -using DeepDrftWeb.Services.Data.Configurations; +using DeepDrftData.Data.Configurations; using Microsoft.EntityFrameworkCore; -namespace DeepDrftWeb.Services.Data; +namespace DeepDrftData.Data; public class DeepDrftContext : DbContext { @@ -15,7 +15,7 @@ public class DeepDrftContext : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - + modelBuilder.ApplyConfiguration(new TrackConfiguration()); } -} \ No newline at end of file +} diff --git a/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs b/DeepDrftData/Data/DeepDrftContextFactory.cs similarity index 96% rename from DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs rename to DeepDrftData/Data/DeepDrftContextFactory.cs index bb846d4..3d417b7 100644 --- a/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs +++ b/DeepDrftData/Data/DeepDrftContextFactory.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; -namespace DeepDrftWeb.Services.Data; +namespace DeepDrftData.Data; public class DeepDrftContextFactory : IDesignTimeDbContextFactory { @@ -19,4 +19,4 @@ public class DeepDrftContextFactory : IDesignTimeDbContextFactory + + diff --git a/DeepDrftWeb.Services/ITrackService.cs b/DeepDrftData/ITrackService.cs similarity index 90% rename from DeepDrftWeb.Services/ITrackService.cs rename to DeepDrftData/ITrackService.cs index 6d387ef..9b70750 100644 --- a/DeepDrftWeb.Services/ITrackService.cs +++ b/DeepDrftData/ITrackService.cs @@ -1,8 +1,8 @@ using DeepDrftModels.Entities; -using DeepDrftModels.Models; +using Models.Common; using NetBlocks.Models; -namespace DeepDrftWeb.Services; +namespace DeepDrftData; public interface ITrackService { diff --git a/DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.Designer.cs b/DeepDrftData/Migrations/20260519021400_InitialCreate.Designer.cs similarity index 77% rename from DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.Designer.cs rename to DeepDrftData/Migrations/20260519021400_InitialCreate.Designer.cs index 4df868a..31111a3 100644 --- a/DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.Designer.cs +++ b/DeepDrftData/Migrations/20260519021400_InitialCreate.Designer.cs @@ -1,6 +1,6 @@ // using System; -using DeepDrftWeb.Services.Data; +using DeepDrftData.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -9,11 +9,11 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace DeepDrftWeb.Migrations +namespace DeepDrftData.Migrations { [DbContext(typeof(DeepDrftContext))] - [Migration("20260518035137_AddCreatedByUserId")] - partial class AddCreatedByUserId + [Migration("20260519021400_InitialCreate")] + partial class InitialCreate { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -45,6 +45,10 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(200)") .HasColumnName("artist"); + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + b.Property("CreatedByUserId") .HasColumnType("bigint") .HasColumnName("created_by_user_id"); @@ -65,6 +69,12 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(500)") .HasColumnName("image_path"); + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted"); + b.Property("ReleaseDate") .HasColumnType("date") .HasColumnName("release_date"); @@ -75,8 +85,15 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(200)") .HasColumnName("track_name"); + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + b.HasKey("Id"); + b.HasIndex("IsDeleted") + .HasDatabaseName("IX_track_is_deleted"); + b.ToTable("track", (string)null); }); #pragma warning restore 612, 618 diff --git a/DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs b/DeepDrftData/Migrations/20260519021400_InitialCreate.cs similarity index 70% rename from DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs rename to DeepDrftData/Migrations/20260519021400_InitialCreate.cs index 2662487..1b7040a 100644 --- a/DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs +++ b/DeepDrftData/Migrations/20260519021400_InitialCreate.cs @@ -4,10 +4,10 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace DeepDrftWeb.Migrations +namespace DeepDrftData.Migrations { /// - public partial class Initial : Migration + public partial class InitialCreate : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -24,12 +24,21 @@ namespace DeepDrftWeb.Migrations album = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), genre = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), release_date = table.Column(type: "date", nullable: true), - image_path = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) + image_path = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + created_by_user_id = table.Column(type: "bigint", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + is_deleted = table.Column(type: "boolean", nullable: false, defaultValue: false) }, constraints: table => { table.PrimaryKey("PK_track", x => x.id); }); + + migrationBuilder.CreateIndex( + name: "IX_track_is_deleted", + table: "track", + column: "is_deleted"); } /// diff --git a/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs b/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs similarity index 79% rename from DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs rename to DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs index 76ae3af..ed99ec0 100644 --- a/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs +++ b/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs @@ -1,6 +1,6 @@ // using System; -using DeepDrftWeb.Services.Data; +using DeepDrftData.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; @@ -8,7 +8,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace DeepDrftWeb.Migrations +namespace DeepDrftData.Migrations { [DbContext(typeof(DeepDrftContext))] partial class DeepDrftContextModelSnapshot : ModelSnapshot @@ -42,6 +42,10 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(200)") .HasColumnName("artist"); + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + b.Property("CreatedByUserId") .HasColumnType("bigint") .HasColumnName("created_by_user_id"); @@ -62,6 +66,12 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(500)") .HasColumnName("image_path"); + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted"); + b.Property("ReleaseDate") .HasColumnType("date") .HasColumnName("release_date"); @@ -72,8 +82,15 @@ namespace DeepDrftWeb.Migrations .HasColumnType("character varying(200)") .HasColumnName("track_name"); + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + b.HasKey("Id"); + b.HasIndex("IsDeleted") + .HasDatabaseName("IX_track_is_deleted"); + b.ToTable("track", (string)null); }); #pragma warning restore 612, 618 diff --git a/DeepDrftData/Repositories/TrackRepository.cs b/DeepDrftData/Repositories/TrackRepository.cs new file mode 100644 index 0000000..878163a --- /dev/null +++ b/DeepDrftData/Repositories/TrackRepository.cs @@ -0,0 +1,31 @@ +using Data.Data.Repositories; +using Data.Errors; +using DeepDrftData.Data; +using DeepDrftModels.Entities; +using Microsoft.Extensions.Logging; + +namespace DeepDrftData.Repositories; + +public class TrackRepository : Repository +{ + public TrackRepository( + DeepDrftContext context, + ILogger> logger, + IDbExceptionClassifier? classifier = null) + : base(context, logger, classifier: classifier) + { + } + + protected override void UpdateEntity(TrackEntity target, TrackEntity source) + { + base.UpdateEntity(target, source); // copies CreatedAt, UpdatedAt, IsDeleted + target.EntryKey = source.EntryKey; + target.TrackName = source.TrackName; + target.Artist = source.Artist; + target.Album = source.Album; + target.Genre = source.Genre; + target.ReleaseDate = source.ReleaseDate; + target.ImagePath = source.ImagePath; + target.CreatedByUserId = source.CreatedByUserId; + } +} diff --git a/DeepDrftData/TrackConverter.cs b/DeepDrftData/TrackConverter.cs new file mode 100644 index 0000000..30e7173 --- /dev/null +++ b/DeepDrftData/TrackConverter.cs @@ -0,0 +1,44 @@ +using DeepDrftModels.DTOs; +using DeepDrftModels.Entities; +using Models.Converters; + +namespace DeepDrftData; + +/// +/// Static entity ↔ DTO converter consumed by the BlazorBlocks Manager base class. +/// The DTO side mirrors the entity field-for-field; the audit columns +/// (CreatedAt, UpdatedAt) come from BaseEntity / BaseModel. +/// IsDeleted does not round-trip — soft-deleted rows are not exposed via the model. +/// +public class TrackConverter : IEntityToModelConverter +{ + public static TrackDto Convert(TrackEntity entity) => new() + { + Id = entity.Id, + CreatedAt = entity.CreatedAt, + UpdatedAt = entity.UpdatedAt, + EntryKey = entity.EntryKey, + TrackName = entity.TrackName, + Artist = entity.Artist, + Album = entity.Album, + Genre = entity.Genre, + ReleaseDate = entity.ReleaseDate, + ImagePath = entity.ImagePath, + CreatedByUserId = entity.CreatedByUserId + }; + + public static TrackEntity Convert(TrackDto model) => new() + { + Id = model.Id, + CreatedAt = model.CreatedAt, + UpdatedAt = model.UpdatedAt, + EntryKey = model.EntryKey, + TrackName = model.TrackName, + Artist = model.Artist, + Album = model.Album, + Genre = model.Genre, + ReleaseDate = model.ReleaseDate, + ImagePath = model.ImagePath, + CreatedByUserId = model.CreatedByUserId + }; +} diff --git a/DeepDrftData/TrackManager.cs b/DeepDrftData/TrackManager.cs new file mode 100644 index 0000000..bf5984b --- /dev/null +++ b/DeepDrftData/TrackManager.cs @@ -0,0 +1,137 @@ +using Data.Managers; +using DeepDrftData.Repositories; +using DeepDrftModels.DTOs; +using DeepDrftModels.Entities; +using Microsoft.Extensions.Logging; +using Models.Common; +using NetBlocks.Models; + +namespace DeepDrftData; + +/// +/// SQL-side track orchestrator built on the BlazorBlocks Manager base. Two surfaces coexist: +/// +/// - The DTO-shaped IManager surface (GetById → TrackDto, etc.) inherited from Manager<>. +/// - The entity-shaped ITrackService surface retained for backward compatibility with the +/// web host, CMS, and CLI — all existing controllers and pages inject ITrackService and +/// expect TrackEntity-typed results. The two GetById overloads conflict on signature, so +/// ITrackService.GetById is implemented explicitly; the base Manager.Delete satisfies +/// both interfaces because the signatures align. +/// +public class TrackManager + : Manager, ITrackService +{ + public TrackManager( + TrackRepository repository, + ILogger> logger) + : base(repository, logger) + { + } + + // --- ITrackService implementation (entity-space; calls Repository directly) --- + + // Explicit interface implementation — IManager.GetById returns ResultContainer + // (inherited from Manager<>), so this entity-typed overload cannot coexist as a public + // member with the same name. Callers always inject ITrackService, so the explicit impl + // resolves correctly at the call site. + async Task> ITrackService.GetById(long id) + { + try + { + var entity = await Repository.GetByIdAsync(id); + return ResultContainer.CreatePassResult(entity); + } + catch (Exception e) + { + return ResultContainer.CreateFailResult(e.Message); + } + } + + public async Task>> GetAll() + { + try + { + var entities = await Repository.GetAllAsync(); + return ResultContainer>.CreatePassResult(entities.ToList()); + } + catch (Exception e) + { + return ResultContainer>.CreateFailResult(e.Message); + } + } + + public async Task>> GetPaged( + int pageNumber, + int pageSize, + string? sortColumn, + bool sortDescending, + CancellationToken cancellationToken = default) + { + try + { + var parameters = new PagingParameters + { + Page = pageNumber, + PageSize = pageSize, + IsDescending = sortDescending, + OrderBy = sortColumn switch + { + "TrackName" => e => e.TrackName, + "Artist" => e => e.Artist, + "Album" => e => (object)(e.Album ?? string.Empty), + "Genre" => e => (object)(e.Genre ?? string.Empty), + "ReleaseDate" => e => (object)(e.ReleaseDate ?? DateOnly.MaxValue), + _ => e => e.Id + } + }; + + var page = await Repository.GetPagedAsync(parameters); + return ResultContainer>.CreatePassResult(page); + } + catch (Exception e) + { + return ResultContainer>.CreateFailResult(e.Message); + } + } + + public async Task> Create(TrackEntity newTrack) + { + try + { + var added = await Repository.AddAsync(newTrack); + return ResultContainer.CreatePassResult(added); + } + catch (Exception e) + { + return ResultContainer.CreateFailResult(e.Message); + } + } + + // Manager<>.Update takes TrackDto and returns Result; this Update keeps the + // entity-typed contract callers expect and returns the post-update entity for the + // existing CMS edit flow that reads back the persisted values. + /// + /// Updates the track's metadata fields and returns the DB-authoritative entity. + /// The caller's object has its UpdatedAt field + /// mutated in place by ; do not reuse it. + /// + public async Task> Update(TrackEntity track) + { + try + { + await Repository.UpdateAsync(track); + var updated = await Repository.GetByIdAsync(track.Id); + return updated is not null + ? ResultContainer.CreatePassResult(updated) + : ResultContainer.CreateFailResult("Track not found after update."); + } + catch (Exception e) + { + return ResultContainer.CreateFailResult(e.Message); + } + } + + // Delete(long) is inherited from Manager<> — its Task signature already + // satisfies ITrackService.Delete, and the base implementation performs the soft delete + // via Repository.DeleteAsync. No override needed. +} diff --git a/DeepDrftHome.sln b/DeepDrftHome.sln index 3f17d88..b214d54 100644 --- a/DeepDrftHome.sln +++ b/DeepDrftHome.sln @@ -14,9 +14,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftTests", "DeepDrftTe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftCli", "DeepDrftCli\DeepDrftCli.csproj", "{E4C0ADD6-1264-47A5-98E1-0843AD14B7F9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftWeb.Services", "DeepDrftWeb.Services\DeepDrftWeb.Services.csproj", "{1D1CE905-DAD0-4E93-9B09-326E8EC05877}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftData", "DeepDrftData\DeepDrftData.csproj", "{1D1CE905-DAD0-4E93-9B09-326E8EC05877}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Services", "DeepDrftContent.Services\DeepDrftContent.Services.csproj", "{4D025326-7F27-4C42-BE0F-92C1E64E0696}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Data", "DeepDrftContent.Data\DeepDrftContent.Data.csproj", "{4D025326-7F27-4C42-BE0F-92C1E64E0696}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftCms", "DeepDrftCms\DeepDrftCms.csproj", "{81F1D47F-F892-45FB-9E35-D7775805FFD3}" EndProject diff --git a/DeepDrftModels/DTOs/TrackDto.cs b/DeepDrftModels/DTOs/TrackDto.cs index f63d8ed..c368262 100644 --- a/DeepDrftModels/DTOs/TrackDto.cs +++ b/DeepDrftModels/DTOs/TrackDto.cs @@ -1,13 +1,21 @@ -namespace DeepDrftModels.DTOs; +using Models.Models; -public class TrackDto +namespace DeepDrftModels.DTOs; + +// Inherits Id, CreatedAt, UpdatedAt from BaseModel (Cerebellum.BlazorBlocks.Models). +// BlazorBlocks's Manager<> generic constraint requires `new()` on the model type, which +// disqualifies `required` properties (the `new()` constraint and required members do not +// compose). EntryKey/TrackName/Artist therefore drop `required` here — the TrackEntity +// side remains required, and TrackConverter assigns every field on the round-trip so an +// empty default is never observable in production code paths. +public class TrackDto : BaseModel { - public long Id { get; set; } - public required string EntryKey { get; set; } - public required string TrackName { get; set; } - public required string Artist { get; set; } + public string EntryKey { get; set; } = string.Empty; + public string TrackName { get; set; } = string.Empty; + public string Artist { get; set; } = string.Empty; public string? Album { get; set; } public string? Genre { get; set; } public DateOnly? ReleaseDate { get; set; } public string? ImagePath { get; set; } -} \ No newline at end of file + public long? CreatedByUserId { get; set; } +} diff --git a/DeepDrftModels/DeepDrftModels.csproj b/DeepDrftModels/DeepDrftModels.csproj index b1a2a1c..bd54bcb 100644 --- a/DeepDrftModels/DeepDrftModels.csproj +++ b/DeepDrftModels/DeepDrftModels.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -8,6 +8,7 @@ + diff --git a/DeepDrftModels/Entities/TrackEntity.cs b/DeepDrftModels/Entities/TrackEntity.cs index 042e5ff..28d8b14 100644 --- a/DeepDrftModels/Entities/TrackEntity.cs +++ b/DeepDrftModels/Entities/TrackEntity.cs @@ -1,8 +1,12 @@ -namespace DeepDrftModels.Entities; +using Models.Entities; -public class TrackEntity +namespace DeepDrftModels.Entities; + +// Inherits Id, CreatedAt, UpdatedAt, IsDeleted from BaseEntity (Cerebellum.BlazorBlocks.Models). +// BaseEntity ships the audit columns but does not declare IEntity itself, so subclasses +// declare it explicitly to satisfy the generic constraints on Repository<>/Manager<>/etc. +public class TrackEntity : BaseEntity, IEntity { - public long Id { get; set; } public required string EntryKey { get; set; } public required string TrackName { get; set; } public required string Artist { get; set; } @@ -11,4 +15,4 @@ public class TrackEntity public DateOnly? ReleaseDate { get; set; } public string? ImagePath { get; set; } public long? CreatedByUserId { get; set; } -} \ No newline at end of file +} diff --git a/DeepDrftModels/Models/PagedResult.cs b/DeepDrftModels/Models/PagedResult.cs deleted file mode 100644 index 46ab081..0000000 --- a/DeepDrftModels/Models/PagedResult.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace DeepDrftModels.Models; - -public class PagedResult -{ - public IEnumerable Items { get; set; } = new List(); - public int TotalCount { get; set; } - public int Page { get; set; } - public int PageSize { get; set; } - public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)TotalCount / PageSize) : 0; - public bool HasNextPage => Page < TotalPages; - public bool HasPreviousPage => Page > 1; - - public PagedResult() - { - } - - public static PagedResult From(PagedResult other, IEnumerable items) - { - return new PagedResult() - { - Items = items.ToList(), - Page = other.Page, - PageSize = other.PageSize, - TotalCount = other.TotalCount, - }; - } - - public PagedResult(IEnumerable items, int totalCount, int page, int pageSize) - { - Items = items.ToList(); - TotalCount = totalCount; - Page = page; - PageSize = pageSize; - } -} \ No newline at end of file diff --git a/DeepDrftModels/Models/PagingParameters.cs b/DeepDrftModels/Models/PagingParameters.cs deleted file mode 100644 index 55c2dd0..0000000 --- a/DeepDrftModels/Models/PagingParameters.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Linq.Expressions; - -namespace DeepDrftModels.Models; - -public class PagingParameters -{ - private const int _maxPageSize = 100; - private int _pageSize = 20; - - public int Page { get; set; } = 1; - - public int PageSize - { - get => _pageSize; - set => _pageSize = value > _maxPageSize ? _maxPageSize : value; - } -} - -public class PagingParameters : PagingParameters -{ - public Expression>? OrderBy { get; set; } - public bool IsDescending { get; set; } = false; - - public int Skip => (Page - 1) * PageSize; -} \ No newline at end of file diff --git a/DeepDrftTests/DeepDrftTests.csproj b/DeepDrftTests/DeepDrftTests.csproj index 91d257c..46c6831 100644 --- a/DeepDrftTests/DeepDrftTests.csproj +++ b/DeepDrftTests/DeepDrftTests.csproj @@ -27,7 +27,7 @@ - + diff --git a/DeepDrftTests/FileDatabaseTests.cs b/DeepDrftTests/FileDatabaseTests.cs index 206266c..7d42fc8 100644 --- a/DeepDrftTests/FileDatabaseTests.cs +++ b/DeepDrftTests/FileDatabaseTests.cs @@ -1,5 +1,5 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; namespace DeepDrftTests; diff --git a/DeepDrftTests/IndexSystemTests.cs b/DeepDrftTests/IndexSystemTests.cs index 5320fd9..552b031 100644 --- a/DeepDrftTests/IndexSystemTests.cs +++ b/DeepDrftTests/IndexSystemTests.cs @@ -1,7 +1,7 @@ -using DeepDrftContent.Services.FileDatabase.Abstractions; -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Abstractions; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Utils; namespace DeepDrftTests; diff --git a/DeepDrftTests/MediaVaultFactoryTests.cs b/DeepDrftTests/MediaVaultFactoryTests.cs index b743620..a4f4f10 100644 --- a/DeepDrftTests/MediaVaultFactoryTests.cs +++ b/DeepDrftTests/MediaVaultFactoryTests.cs @@ -1,5 +1,5 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; namespace DeepDrftTests; diff --git a/DeepDrftTests/MediaVaultTests.cs b/DeepDrftTests/MediaVaultTests.cs index ff28ffe..0d07b07 100644 --- a/DeepDrftTests/MediaVaultTests.cs +++ b/DeepDrftTests/MediaVaultTests.cs @@ -1,6 +1,6 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Utils; namespace DeepDrftTests; diff --git a/DeepDrftTests/ModelTests.cs b/DeepDrftTests/ModelTests.cs index 1fb7710..3d5a406 100644 --- a/DeepDrftTests/ModelTests.cs +++ b/DeepDrftTests/ModelTests.cs @@ -1,4 +1,4 @@ -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; namespace DeepDrftTests; diff --git a/DeepDrftTests/SimpleMediaTypeRegistryTests.cs b/DeepDrftTests/SimpleMediaTypeRegistryTests.cs index 62849d3..8401be4 100644 --- a/DeepDrftTests/SimpleMediaTypeRegistryTests.cs +++ b/DeepDrftTests/SimpleMediaTypeRegistryTests.cs @@ -1,5 +1,5 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Services; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Services; namespace DeepDrftTests; diff --git a/DeepDrftTests/TestData.cs b/DeepDrftTests/TestData.cs index 2464862..00af156 100644 --- a/DeepDrftTests/TestData.cs +++ b/DeepDrftTests/TestData.cs @@ -1,4 +1,4 @@ -using DeepDrftContent.Services.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Models; namespace DeepDrftTests; diff --git a/DeepDrftTests/UtilityTests.cs b/DeepDrftTests/UtilityTests.cs index 876e4ef..daade11 100644 --- a/DeepDrftTests/UtilityTests.cs +++ b/DeepDrftTests/UtilityTests.cs @@ -1,5 +1,5 @@ -using DeepDrftContent.Services.FileDatabase.Models; -using DeepDrftContent.Services.FileDatabase.Utils; +using DeepDrftContent.Data.FileDatabase.Models; +using DeepDrftContent.Data.FileDatabase.Utils; namespace DeepDrftTests; diff --git a/DeepDrftWeb.Client/Clients/TrackClient.cs b/DeepDrftWeb.Client/Clients/TrackClient.cs index eba3f18..299dba8 100644 --- a/DeepDrftWeb.Client/Clients/TrackClient.cs +++ b/DeepDrftWeb.Client/Clients/TrackClient.cs @@ -1,5 +1,5 @@ using DeepDrftModels.Entities; -using DeepDrftModels.Models; +using Models.Common; using NetBlocks.Models; using System.Text.Json; using System.Web; diff --git a/DeepDrftWeb.Client/Pages/TracksView.razor.cs b/DeepDrftWeb.Client/Pages/TracksView.razor.cs index e0efc9f..5075afc 100644 --- a/DeepDrftWeb.Client/Pages/TracksView.razor.cs +++ b/DeepDrftWeb.Client/Pages/TracksView.razor.cs @@ -1,8 +1,8 @@ using DeepDrftModels.Entities; -using DeepDrftModels.Models; using DeepDrftWeb.Client.Services; using DeepDrftWeb.Client.ViewModels; using Microsoft.AspNetCore.Components; +using Models.Common; namespace DeepDrftWeb.Client.Pages; diff --git a/DeepDrftWeb.Client/ViewModels/TracksViewModel.cs b/DeepDrftWeb.Client/ViewModels/TracksViewModel.cs index 7baae2d..0691c43 100644 --- a/DeepDrftWeb.Client/ViewModels/TracksViewModel.cs +++ b/DeepDrftWeb.Client/ViewModels/TracksViewModel.cs @@ -1,6 +1,6 @@ using DeepDrftModels.Entities; -using DeepDrftModels.Models; using DeepDrftWeb.Client.Clients; +using Models.Common; namespace DeepDrftWeb.Client.ViewModels; diff --git a/DeepDrftWeb.Services/Data/Configurations/TrackConfiguration.cs b/DeepDrftWeb.Services/Data/Configurations/TrackConfiguration.cs deleted file mode 100644 index 3f11d84..0000000 --- a/DeepDrftWeb.Services/Data/Configurations/TrackConfiguration.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DeepDrftModels.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace DeepDrftWeb.Services.Data.Configurations; - -public class TrackConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("track"); - - builder.HasKey(x => x.Id); - - builder.Property(x => x.Id) - .HasColumnName("id") - .IsRequired(); - - builder.Property(x => x.EntryKey) - .HasColumnName("entry_key") - .IsRequired() - .HasMaxLength(100); - - builder.Property(x => x.TrackName) - .HasColumnName("track_name") - .IsRequired() - .HasMaxLength(200); - - builder.Property(x => x.Artist) - .HasColumnName("artist") - .IsRequired() - .HasMaxLength(200); - - builder.Property(x => x.Album) - .HasColumnName("album") - .HasMaxLength(200); - - builder.Property(x => x.Genre) - .HasColumnName("genre") - .HasMaxLength(100); - - builder.Property(x => x.ReleaseDate) - .HasColumnName("release_date"); - - builder.Property(x => x.ImagePath) - .HasColumnName("image_path") - .HasMaxLength(500); - - builder.Property(x => x.CreatedByUserId) - .HasColumnName("created_by_user_id"); - } -} \ No newline at end of file diff --git a/DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs b/DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs deleted file mode 100644 index 1be11d7..0000000 --- a/DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs +++ /dev/null @@ -1,81 +0,0 @@ -// -using System; -using DeepDrftWeb.Services.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DeepDrftWeb.Migrations -{ - [DbContext(typeof(DeepDrftContext))] - [Migration("20260518025102_Initial")] - partial class Initial - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.4") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DeepDrftModels.Entities.TrackEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Album") - .HasMaxLength(200) - .HasColumnType("character varying(200)") - .HasColumnName("album"); - - b.Property("Artist") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)") - .HasColumnName("artist"); - - b.Property("EntryKey") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("entry_key"); - - b.Property("Genre") - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("genre"); - - b.Property("ImagePath") - .HasMaxLength(500) - .HasColumnType("character varying(500)") - .HasColumnName("image_path"); - - b.Property("ReleaseDate") - .HasColumnType("date") - .HasColumnName("release_date"); - - b.Property("TrackName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)") - .HasColumnName("track_name"); - - b.HasKey("Id"); - - b.ToTable("track", (string)null); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.cs b/DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.cs deleted file mode 100644 index d1a16a7..0000000 --- a/DeepDrftWeb.Services/Migrations/20260518035137_AddCreatedByUserId.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DeepDrftWeb.Migrations -{ - /// - public partial class AddCreatedByUserId : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "created_by_user_id", - table: "track", - type: "bigint", - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "created_by_user_id", - table: "track"); - } - } -} diff --git a/DeepDrftWeb.Services/Repositories/TrackRepository.cs b/DeepDrftWeb.Services/Repositories/TrackRepository.cs deleted file mode 100644 index 8399d4e..0000000 --- a/DeepDrftWeb.Services/Repositories/TrackRepository.cs +++ /dev/null @@ -1,84 +0,0 @@ -using DeepDrftModels.Entities; -using DeepDrftModels.Models; -using Microsoft.EntityFrameworkCore; -using DeepDrftWeb.Services.Data; - -namespace DeepDrftWeb.Services.Repositories; - -public class TrackRepository -{ - private readonly DeepDrftContext _db; - - public TrackRepository(DeepDrftContext db) - { - _db = db; - } - - public async Task GetById(long id) - { - return await _db.Tracks.FindAsync(id); - } - - public async Task> GetAll() - { - return await _db.Tracks.ToListAsync(); - } - - public async Task> GetPage(PagingParameters pageParameters, CancellationToken cancellationToken = default) - { - // Two separate queries with no transaction: count and page can be momentarily inconsistent - // under concurrent writes. Acceptable — write volume is low and the UI is read-only. - // If filtering is added, the count query must be updated to apply the same filter. - var count = await _db.Tracks.CountAsync(cancellationToken); - - var orderBy = pageParameters.OrderBy ?? (t => t.Id); - var ordered = pageParameters.IsDescending - ? _db.Tracks.OrderByDescending(orderBy) - : _db.Tracks.OrderBy(orderBy); - - var page = await ordered - .Skip(pageParameters.Skip) - .Take(pageParameters.PageSize) - .ToListAsync(cancellationToken); - - return new PagedResult(page, count, pageParameters.Page, pageParameters.PageSize); - } - - public async Task Create(TrackEntity newTrack) - { - var track = _db.Tracks.Add(newTrack); - await _db.SaveChangesAsync(); - return track.Entity; - } - - public async Task Update(TrackEntity track) - { - var trackEntity = await GetById(track.Id); - - if (trackEntity == null) - { - throw new InvalidOperationException($"Track not found: {track.Id}"); - } - - trackEntity.Album = track.Album; - trackEntity.Artist = track.Artist; - trackEntity.Genre = track.Genre; - trackEntity.ImagePath = track.ImagePath; - trackEntity.EntryKey = track.EntryKey; - trackEntity.ReleaseDate = track.ReleaseDate; - trackEntity.TrackName = track.TrackName; - - await _db.SaveChangesAsync(); - return trackEntity; - } - - public async Task Delete(long id) - { - var track = await GetById(id); - if (track != null) - { - _db.Tracks.Remove(track); - await _db.SaveChangesAsync(); - } - } -} \ No newline at end of file diff --git a/DeepDrftWeb.Services/TrackService.cs b/DeepDrftWeb.Services/TrackService.cs deleted file mode 100644 index e1cd6ad..0000000 --- a/DeepDrftWeb.Services/TrackService.cs +++ /dev/null @@ -1,125 +0,0 @@ -using DeepDrftModels.Entities; -using DeepDrftModels.Models; -using DeepDrftWeb.Services.Data; -using DeepDrftWeb.Services.Repositories; -using NetBlocks.Models; - -namespace DeepDrftWeb.Services; - -public class TrackService : ITrackService -{ - private readonly TrackRepository _repository; - - public TrackService(TrackRepository repository) - { - _repository = repository; - } - - public async Task> GetById(long id) - { - try - { - var track = await _repository.GetById(id); - return ResultContainer.CreatePassResult(track); - } - catch (Exception e) - { - return ResultContainer.CreateFailResult(e.Message); - } - } - - public async Task>> GetAll() - { - try - { - var tracks = await _repository.GetAll(); - return ResultContainer>.CreatePassResult(tracks); - } - catch (Exception e) - { - return ResultContainer>.CreateFailResult(e.Message); - } - } - - public async Task>> GetPaged(int pageNumber, int pageSize, string? sortColumn, bool sortDescending, CancellationToken cancellationToken = default) - { - try - { - var parameters = new PagingParameters() - { - Page = pageNumber, - PageSize = pageSize, - IsDescending = sortDescending - }; - - if (sortColumn != null) - { - switch (sortColumn) - { - case "TrackName": - parameters.OrderBy = entity => entity.TrackName; - break; - case "Artist": - parameters.OrderBy = entity => entity.Artist; - break; - case "Album": - parameters.OrderBy = entity => entity.Album ?? ""; - break; - case "ReleaseDate": - parameters.OrderBy = entity => entity.ReleaseDate ?? DateOnly.MaxValue; - break; - case "Genre": - parameters.OrderBy = entity => entity.Genre ?? ""; - break; - - } - } - - var page = await _repository.GetPage(parameters, cancellationToken); - return ResultContainer>.CreatePassResult(page); - } - catch (Exception e) - { - return ResultContainer>.CreateFailResult(e.Message); - } - } - - public async Task> Create(TrackEntity newTrack) - { - try - { - var track = await _repository.Create(newTrack); - return ResultContainer.CreatePassResult(track); - } - catch (Exception e) - { - return ResultContainer.CreateFailResult(e.Message); - } - } - - public async Task> Update(TrackEntity track) - { - try - { - var updatedTrack = await _repository.Update(track); - return ResultContainer.CreatePassResult(updatedTrack); - } - catch (Exception e) - { - return ResultContainer.CreateFailResult(e.Message); - } - } - - public async Task Delete(long id) - { - try - { - await _repository.Delete(id); - return Result.CreatePassResult(); - } - catch (Exception e) - { - return Result.CreateFailResult(e.Message); - } - } -} \ No newline at end of file diff --git a/DeepDrftWeb/Controllers/CmsDeleteController.cs b/DeepDrftWeb/Controllers/CmsDeleteController.cs index 943c765..269fe94 100644 --- a/DeepDrftWeb/Controllers/CmsDeleteController.cs +++ b/DeepDrftWeb/Controllers/CmsDeleteController.cs @@ -1,4 +1,4 @@ -using DeepDrftWeb.Services; +using DeepDrftData; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/DeepDrftWeb/Controllers/CmsEditController.cs b/DeepDrftWeb/Controllers/CmsEditController.cs index d9d088b..49667b0 100644 --- a/DeepDrftWeb/Controllers/CmsEditController.cs +++ b/DeepDrftWeb/Controllers/CmsEditController.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; +using DeepDrftData; using DeepDrftModels.Entities; -using DeepDrftWeb.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using NetBlocks.Models; diff --git a/DeepDrftWeb/Controllers/CmsUploadController.cs b/DeepDrftWeb/Controllers/CmsUploadController.cs index 2bc617f..82f327d 100644 --- a/DeepDrftWeb/Controllers/CmsUploadController.cs +++ b/DeepDrftWeb/Controllers/CmsUploadController.cs @@ -1,7 +1,7 @@ using System.Net.Http.Headers; using System.Security.Claims; +using DeepDrftData; using DeepDrftModels.Entities; -using DeepDrftWeb.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -10,7 +10,7 @@ namespace DeepDrftWeb.Controllers; /// /// CMS upload surface. Proxies a WAV + metadata multipart form to DeepDrftContent's /// POST api/track/upload, then persists the returned unpersisted TrackEntity to SQL via -/// ITrackService.Create. DeepDrftWeb intentionally does not reference DeepDrftContent.Services +/// ITrackService.Create. DeepDrftWeb intentionally does not reference DeepDrftContent.Data /// (CMS-PLAN §5, Option B) — all vault access is over HTTP. /// [ApiController] diff --git a/DeepDrftWeb/Controllers/TrackController.cs b/DeepDrftWeb/Controllers/TrackController.cs index 1bbe995..d4c7f0a 100644 --- a/DeepDrftWeb/Controllers/TrackController.cs +++ b/DeepDrftWeb/Controllers/TrackController.cs @@ -1,7 +1,7 @@ -using DeepDrftModels.Entities; -using DeepDrftModels.Models; -using DeepDrftWeb.Services; +using DeepDrftData; +using DeepDrftModels.Entities; using Microsoft.AspNetCore.Mvc; +using Models.Common; using NetBlocks.Models; namespace DeepDrftWeb.Controllers; diff --git a/DeepDrftWeb/DeepDrftWeb.csproj b/DeepDrftWeb/DeepDrftWeb.csproj index 5dd4e98..b64ef6f 100644 --- a/DeepDrftWeb/DeepDrftWeb.csproj +++ b/DeepDrftWeb/DeepDrftWeb.csproj @@ -25,7 +25,7 @@ - + diff --git a/DeepDrftWeb/Startup.cs b/DeepDrftWeb/Startup.cs index 2e03d45..1331bb7 100644 --- a/DeepDrftWeb/Startup.cs +++ b/DeepDrftWeb/Startup.cs @@ -1,6 +1,7 @@ -using DeepDrftWeb.Services.Data; -using DeepDrftWeb.Services.Repositories; -using DeepDrftWeb.Services; +using DeepDrftData; +using DeepDrftData.Data; +using DeepDrftData.Repositories; +using DeepDrftWeb.Services; // DarkModeService namespace (within this host project) using Microsoft.EntityFrameworkCore; namespace DeepDrftWeb; @@ -26,10 +27,14 @@ public static class Startup .AddHttpContextAccessor() .AddScoped(); - // Add Track services + // Add Track services. TrackManager implements ITrackService for backward compatibility + // with controllers and CMS pages that inject the interface; resolving ITrackService + // returns the same scoped TrackManager instance so the manager surface (DTO-space) + // and the service surface (entity-space) share state. builder.Services .AddScoped() - .AddScoped(); + .AddScoped() + .AddScoped(sp => sp.GetRequiredService()); // CMS → DeepDrftContent client. The API key is required up front (no lazy resolution) // so a misconfiguration surfaces at startup instead of on the first delete attempt. @@ -44,13 +49,13 @@ public static class Startup client.DefaultRequestHeaders.Add("ApiKey", contentApiKey); }); } - + public static string GetKestrelUrl(this WebApplicationBuilder builder) { // Check all the places Kestrel URL can be configured - var urls = builder.Configuration["ASPNETCORE_URLS"] + var urls = builder.Configuration["ASPNETCORE_URLS"] ?? builder.Configuration["urls"]; - + if (!string.IsNullOrEmpty(urls)) { return urls.Split(';')[0].Trim(); @@ -60,15 +65,15 @@ public static class Startup var kestrelSection = builder.Configuration.GetSection("Kestrel:Endpoints"); var firstEndpoint = kestrelSection.GetChildren().FirstOrDefault(); var endpointUrl = firstEndpoint?["Url"]; - + if (!string.IsNullOrEmpty(endpointUrl)) { return endpointUrl; } // ASP.NET Core defaults - return builder.Environment.IsDevelopment() - ? "https://localhost:5001" + return builder.Environment.IsDevelopment() + ? "https://localhost:5001" : "http://localhost:5000"; } -} \ No newline at end of file +} diff --git a/NuGet.Config b/NuGet.Config index db26aa3..7bde569 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -4,5 +4,6 @@ + diff --git a/WebAPI.sln b/WebAPI.sln index b4ec7f9..e53d5c2 100644 --- a/WebAPI.sln +++ b/WebAPI.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Services", "DeepDrftContent.Services\DeepDrftContent.Services.csproj", "{9C5D844B-46A6-4C70-B5A7-3A028795629C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent.Data", "DeepDrftContent.Data\DeepDrftContent.Data.csproj", "{9C5D844B-46A6-4C70-B5A7-3A028795629C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftContent", "DeepDrftContent\DeepDrftContent.csproj", "{91F52E3A-D36D-47C3-924B-2A3CE3606B03}" EndProject diff --git a/WebUI.sln b/WebUI.sln index 2571ef6..e7bf1bf 100644 --- a/WebUI.sln +++ b/WebUI.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftWeb.Services", "DeepDrftWeb.Services\DeepDrftWeb.Services.csproj", "{0B1ABD2E-ACC4-40B2-A80E-CC47CF209C74}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftData", "DeepDrftData\DeepDrftData.csproj", "{0B1ABD2E-ACC4-40B2-A80E-CC47CF209C74}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeepDrftModels", "DeepDrftModels\DeepDrftModels.csproj", "{2507F960-A210-40A3-999D-368A6D067350}" EndProject