feat: replace Redis with PostgreSQL for caching, rate limiting, SMS codes, and token blacklist
- Add 4 PG entities: VerificationCode, RateLimitEntry, TokenBlacklistEntry, CacheEntry - Add 4 services: VerificationService, RateLimitService, TokenBlacklistService, CacheService - Add CleanupBackgroundService for periodic expired data cleanup - Add MigrationHelper for safe schema migration without data loss - Update AuthController: real SMS code generation, rate limiting, logout endpoint with JWT blacklist - Update JwtProvider: add JTI claim for token revocation - Update Program.cs: register new services, JWT blacklist validation, DB migration - Remove StackExchange.Redis NuGet package and all Redis config references - Update start-dev.bat: 6→5 services, remove Redis startup - Update docs: remove Redis references from all documentation - Fix: logout button spacing on profile page - Fix: .gitignore data/→/data/ to not ignore Infrastructure/Data/
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HealthManager.Infrastructure.Data;
|
||||
|
||||
public static class MigrationHelper
|
||||
{
|
||||
public static async Task EnsureNewTablesAsync(AppDbContext db)
|
||||
{
|
||||
var sql = """
|
||||
CREATE TABLE IF NOT EXISTS "VerificationCodes" (
|
||||
"Id" uuid PRIMARY KEY,
|
||||
"Phone" text NOT NULL,
|
||||
"Code" text NOT NULL,
|
||||
"Type" text NOT NULL DEFAULT 'login',
|
||||
"ExpiresAt" timestamptz NOT NULL,
|
||||
"IsUsed" boolean NOT NULL DEFAULT FALSE,
|
||||
"CreatedAt" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS "IX_VerificationCodes_ExpiresAt" ON "VerificationCodes" ("ExpiresAt");
|
||||
CREATE INDEX IF NOT EXISTS "IX_VerificationCodes_Phone_Type" ON "VerificationCodes" ("Phone", "Type");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "RateLimitEntries" (
|
||||
"Id" uuid PRIMARY KEY,
|
||||
"Key" text NOT NULL,
|
||||
"Count" integer NOT NULL,
|
||||
"WindowStart" timestamptz NOT NULL,
|
||||
"ExpiresAt" timestamptz NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "IX_RateLimitEntries_Key_WindowStart" ON "RateLimitEntries" ("Key", "WindowStart");
|
||||
CREATE INDEX IF NOT EXISTS "IX_RateLimitEntries_ExpiresAt" ON "RateLimitEntries" ("ExpiresAt");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "TokenBlacklistEntries" (
|
||||
"Id" uuid PRIMARY KEY,
|
||||
"Jti" text NOT NULL,
|
||||
"UserId" uuid NOT NULL,
|
||||
"ExpiresAt" timestamptz NOT NULL,
|
||||
"CreatedAt" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "IX_TokenBlacklistEntries_Jti" ON "TokenBlacklistEntries" ("Jti");
|
||||
CREATE INDEX IF NOT EXISTS "IX_TokenBlacklistEntries_ExpiresAt" ON "TokenBlacklistEntries" ("ExpiresAt");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "CacheEntries" (
|
||||
"Id" uuid PRIMARY KEY,
|
||||
"Key" text NOT NULL,
|
||||
"Value" jsonb NOT NULL,
|
||||
"ExpiresAt" timestamptz NOT NULL,
|
||||
"CreatedAt" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "IX_CacheEntries_Key" ON "CacheEntries" ("Key");
|
||||
CREATE INDEX IF NOT EXISTS "IX_CacheEntries_ExpiresAt" ON "CacheEntries" ("ExpiresAt");
|
||||
""";
|
||||
|
||||
await db.Database.ExecuteSqlRawAsync(sql);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user