diff --git a/.gitignore b/.gitignore
index 3bb1dc7..a67d0b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -297,6 +297,7 @@ __pycache__/
# Environment Secrets
**/environment
+**/appsettings.Development.json
# local sqlite files
**/deepdrft.db*
diff --git a/DeepDrftCli/DeepDrftCli.csproj b/DeepDrftCli/DeepDrftCli.csproj
index 1ca1e16..d7dfa06 100644
--- a/DeepDrftCli/DeepDrftCli.csproj
+++ b/DeepDrftCli/DeepDrftCli.csproj
@@ -8,14 +8,15 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/DeepDrftCli/Program.cs b/DeepDrftCli/Program.cs
index 117b010..a265998 100644
--- a/DeepDrftCli/Program.cs
+++ b/DeepDrftCli/Program.cs
@@ -22,7 +22,7 @@ builder.Services.AddLogging(configure => configure.AddConsole());
// Add database context
builder.Services.AddDbContext(options =>
- options.UseSqlite(cliSettings.ConnectionString));
+ options.UseNpgsql(cliSettings.ConnectionString));
// Add FileDatabase
builder.Services.AddSingleton(provider =>
diff --git a/DeepDrftModels/DeepDrftModels.csproj b/DeepDrftModels/DeepDrftModels.csproj
index cb70a35..f7f66b9 100644
--- a/DeepDrftModels/DeepDrftModels.csproj
+++ b/DeepDrftModels/DeepDrftModels.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs b/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs
index f2f8bfd..97084ab 100644
--- a/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs
+++ b/DeepDrftWeb.Services/Data/DeepDrftContextFactory.cs
@@ -7,9 +7,16 @@ public class DeepDrftContextFactory : IDesignTimeDbContextFactory();
- optionsBuilder.UseSqlite("Data Source=../Database/deepdrft.db");
-
+ optionsBuilder.UseNpgsql(connectionString);
+
return new DeepDrftContext(optionsBuilder.Options);
}
}
\ No newline at end of file
diff --git a/DeepDrftWeb.Services/DeepDrftWeb.Services.csproj b/DeepDrftWeb.Services/DeepDrftWeb.Services.csproj
index c923130..26da6f1 100644
--- a/DeepDrftWeb.Services/DeepDrftWeb.Services.csproj
+++ b/DeepDrftWeb.Services/DeepDrftWeb.Services.csproj
@@ -1,4 +1,4 @@
-
+
net10.0
@@ -7,12 +7,17 @@
-
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/DeepDrftWeb.Services/Migrations/20250904233927_Initial.cs b/DeepDrftWeb.Services/Migrations/20250904233927_Initial.cs
deleted file mode 100644
index 0d937b3..0000000
--- a/DeepDrftWeb.Services/Migrations/20250904233927_Initial.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
-
-#nullable disable
-
-namespace DeepDrftWeb.Migrations
-{
- ///
- public partial class Initial : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "track",
- columns: table => new
- {
- id = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
- entry_key = table.Column(type: "TEXT", maxLength: 100, nullable: false),
- track_name = table.Column(type: "TEXT", maxLength: 200, nullable: false),
- artist = table.Column(type: "TEXT", maxLength: 200, nullable: false),
- album = table.Column(type: "TEXT", maxLength: 200, nullable: true),
- genre = table.Column(type: "TEXT", maxLength: 100, nullable: true),
- release_date = table.Column(type: "TEXT", nullable: true),
- image_path = table.Column(type: "TEXT", maxLength: 500, nullable: true)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_track", x => x.id);
- });
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(
- name: "track");
- }
- }
-}
diff --git a/DeepDrftWeb.Services/Migrations/20250904233927_Initial.Designer.cs b/DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs
similarity index 68%
rename from DeepDrftWeb.Services/Migrations/20250904233927_Initial.Designer.cs
rename to DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs
index b652a07..1be11d7 100644
--- a/DeepDrftWeb.Services/Migrations/20250904233927_Initial.Designer.cs
+++ b/DeepDrftWeb.Services/Migrations/20260518025102_Initial.Designer.cs
@@ -5,63 +5,70 @@ 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("20250904233927_Initial")]
+ [Migration("20260518025102_Initial")]
partial class Initial
{
///
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "9.0.8");
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("DeepDrftModels.Entities.TrackEntity", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
- .HasColumnType("INTEGER")
+ .HasColumnType("bigint")
.HasColumnName("id");
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
b.Property("Album")
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("album");
b.Property("Artist")
.IsRequired()
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("artist");
b.Property("EntryKey")
.IsRequired()
.HasMaxLength(100)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(100)")
.HasColumnName("entry_key");
b.Property("Genre")
.HasMaxLength(100)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(100)")
.HasColumnName("genre");
b.Property("ImagePath")
.HasMaxLength(500)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(500)")
.HasColumnName("image_path");
b.Property("ReleaseDate")
- .HasColumnType("TEXT")
+ .HasColumnType("date")
.HasColumnName("release_date");
b.Property("TrackName")
.IsRequired()
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("track_name");
b.HasKey("Id");
diff --git a/DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs b/DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs
new file mode 100644
index 0000000..2662487
--- /dev/null
+++ b/DeepDrftWeb.Services/Migrations/20260518025102_Initial.cs
@@ -0,0 +1,42 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace DeepDrftWeb.Migrations
+{
+ ///
+ public partial class Initial : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "track",
+ columns: table => new
+ {
+ id = table.Column(type: "bigint", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ entry_key = table.Column(type: "character varying(100)", maxLength: 100, nullable: false),
+ track_name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false),
+ artist = table.Column(type: "character varying(200)", maxLength: 200, nullable: false),
+ 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)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_track", x => x.id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "track");
+ }
+ }
+}
diff --git a/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs b/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs
index 36cb1f3..e795600 100644
--- a/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs
+++ b/DeepDrftWeb.Services/Migrations/DeepDrftContextModelSnapshot.cs
@@ -4,6 +4,7 @@ using DeepDrftWeb.Services.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
@@ -15,50 +16,56 @@ namespace DeepDrftWeb.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "9.0.8");
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("DeepDrftModels.Entities.TrackEntity", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
- .HasColumnType("INTEGER")
+ .HasColumnType("bigint")
.HasColumnName("id");
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
b.Property("Album")
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("album");
b.Property("Artist")
.IsRequired()
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("artist");
b.Property("EntryKey")
.IsRequired()
.HasMaxLength(100)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(100)")
.HasColumnName("entry_key");
b.Property("Genre")
.HasMaxLength(100)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(100)")
.HasColumnName("genre");
b.Property("ImagePath")
.HasMaxLength(500)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(500)")
.HasColumnName("image_path");
b.Property("ReleaseDate")
- .HasColumnType("TEXT")
+ .HasColumnType("date")
.HasColumnName("release_date");
b.Property("TrackName")
.IsRequired()
.HasMaxLength(200)
- .HasColumnType("TEXT")
+ .HasColumnType("character varying(200)")
.HasColumnName("track_name");
b.HasKey("Id");
diff --git a/DeepDrftWeb.Services/Repositories/TrackRepository.cs b/DeepDrftWeb.Services/Repositories/TrackRepository.cs
index 69972a5..d4cb123 100644
--- a/DeepDrftWeb.Services/Repositories/TrackRepository.cs
+++ b/DeepDrftWeb.Services/Repositories/TrackRepository.cs
@@ -27,7 +27,7 @@ public class TrackRepository
public async Task> GetPage(PagingParameters pageParameters)
{
// Two separate queries with no transaction: count and page can be momentarily inconsistent
- // under concurrent writes. Acceptable — SQLite concurrency is low and the UI is read-only.
+ // 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();
diff --git a/DeepDrftWeb/DeepDrftWeb.csproj b/DeepDrftWeb/DeepDrftWeb.csproj
index 8db9af4..f50f99b 100644
--- a/DeepDrftWeb/DeepDrftWeb.csproj
+++ b/DeepDrftWeb/DeepDrftWeb.csproj
@@ -8,17 +8,18 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/DeepDrftWeb/Startup.cs b/DeepDrftWeb/Startup.cs
index f762135..c72c28c 100644
--- a/DeepDrftWeb/Startup.cs
+++ b/DeepDrftWeb/Startup.cs
@@ -11,7 +11,7 @@ public static class Startup
{
// Add Entity Framework services
builder.Services.AddDbContext(options =>
- options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
+ options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
// Add Server Prerendering Theming Support
// DarkModeSettings is registered in DeepDrftWeb.Client.Startup.ConfigureDomainServices
diff --git a/DeepDrftWeb/appsettings.Development.json b/DeepDrftWeb/appsettings.Development.json
deleted file mode 100644
index 88066b5..0000000
--- a/DeepDrftWeb/appsettings.Development.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning",
- "DeepDrftWeb.Client.Services.StreamingAudioPlayerService": "Debug"
- },
- "Console": {
- "FormatterName": "simple",
- "LogLevel": {
- "Default": "Information"
- }
- }
- },
- "DetailedErrors": true,
- "ApiUrls": {
- "ContentApi": "http://localhost:54494/"
- }
-}
diff --git a/DeepDrftWeb/appsettings.json b/DeepDrftWeb/appsettings.json
index cb978c1..7b8bb3f 100644
--- a/DeepDrftWeb/appsettings.json
+++ b/DeepDrftWeb/appsettings.json
@@ -7,7 +7,7 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
- "DefaultConnection": "Data Source=../Database/deepdrft.db"
+ "DefaultConnection": "Host=localhost;Database=deepdrft_dev;Username=postgres;Password=REPLACE_IN_ENV"
},
"ApiUrls": {
"ContentApi": "http://localhost:12777/"
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..9f7d2ac
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,14 @@
+services:
+ postgres:
+ image: postgres:17
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: deepdrft_dev
+ ports:
+ - "5432:5432"
+ volumes:
+ - deepdrft_postgres:/var/lib/postgresql/data
+
+volumes:
+ deepdrft_postgres: