SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF OBJECT_ID(N'dbo.IllustrationLibraryItems', N'U') IS NULL BEGIN CREATE TABLE dbo.IllustrationLibraryItems ( IllustrationLibraryItemID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_IllustrationLibraryItems PRIMARY KEY, Category nvarchar(40) NOT NULL, StableCode nvarchar(120) NOT NULL, DisplayTitle nvarchar(200) NOT NULL, ShortDescription nvarchar(500) NULL, MetadataJson nvarchar(max) NULL, SpecificationJson nvarchar(max) NULL, FilePath nvarchar(500) NULL, ThumbnailPath nvarchar(500) NULL, Width int NULL, Height int NULL, FileSizeBytes bigint NULL, MimeType nvarchar(100) NULL, Status nvarchar(40) NOT NULL CONSTRAINT DF_IllustrationLibraryItems_Status DEFAULT N'Planned', IsActive bit NOT NULL CONSTRAINT DF_IllustrationLibraryItems_IsActive DEFAULT 1, IsApproved bit NOT NULL CONSTRAINT DF_IllustrationLibraryItems_IsApproved DEFAULT 0, CreatedUtc datetime2(0) NOT NULL CONSTRAINT DF_IllustrationLibraryItems_CreatedUtc DEFAULT SYSUTCDATETIME(), UpdatedUtc datetime2(0) NOT NULL CONSTRAINT DF_IllustrationLibraryItems_UpdatedUtc DEFAULT SYSUTCDATETIME(), ApprovedUtc datetime2(0) NULL, ApprovedByUserID int NULL, Provider nvarchar(80) NULL, Model nvarchar(120) NULL, PromptText nvarchar(max) NULL, PromptTemplateVersion nvarchar(40) NULL, ProviderRequestID nvarchar(160) NULL, AttemptCount int NOT NULL CONSTRAINT DF_IllustrationLibraryItems_AttemptCount DEFAULT 0, ParentItemID int NULL, RejectionReason nvarchar(500) NULL, AdminNotes nvarchar(1000) NULL, UsageCount int NOT NULL CONSTRAINT DF_IllustrationLibraryItems_UsageCount DEFAULT 0, LastError nvarchar(1000) NULL, QueuedUtc datetime2(0) NULL, StartedUtc datetime2(0) NULL, CompletedUtc datetime2(0) NULL, CONSTRAINT CK_IllustrationLibraryItems_Category CHECK (Category IN (N'Character', N'Location', N'Asset')), CONSTRAINT CK_IllustrationLibraryItems_Status CHECK (Status IN (N'Planned', N'Queued', N'Generating', N'Generated', N'Approved', N'Rejected', N'Failed', N'Disabled')) ); END; GO IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_IllustrationLibraryItems_Parent') BEGIN ALTER TABLE dbo.IllustrationLibraryItems ADD CONSTRAINT FK_IllustrationLibraryItems_Parent FOREIGN KEY (ParentItemID) REFERENCES dbo.IllustrationLibraryItems(IllustrationLibraryItemID); END; GO IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_IllustrationLibraryItems_ApprovedBy') AND OBJECT_ID(N'dbo.AppUser', N'U') IS NOT NULL BEGIN ALTER TABLE dbo.IllustrationLibraryItems ADD CONSTRAINT FK_IllustrationLibraryItems_ApprovedBy FOREIGN KEY (ApprovedByUserID) REFERENCES dbo.AppUser(UserID); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_IllustrationLibraryItems_Status' AND object_id = OBJECT_ID(N'dbo.IllustrationLibraryItems')) CREATE INDEX IX_IllustrationLibraryItems_Status ON dbo.IllustrationLibraryItems(Status, Category, UpdatedUtc DESC); GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_IllustrationLibraryItems_Code' AND object_id = OBJECT_ID(N'dbo.IllustrationLibraryItems')) CREATE INDEX IX_IllustrationLibraryItems_Code ON dbo.IllustrationLibraryItems(StableCode, Status, IsActive); GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_IllustrationLibraryItems_ActivePlannedCode' AND object_id = OBJECT_ID(N'dbo.IllustrationLibraryItems')) CREATE UNIQUE INDEX UX_IllustrationLibraryItems_ActivePlannedCode ON dbo.IllustrationLibraryItems(StableCode) WHERE ParentItemID IS NULL AND Status IN (N'Planned', N'Queued', N'Generating', N'Generated', N'Approved') AND IsActive = 1; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_List @Category nvarchar(40) = NULL, @Status nvarchar(40) = NULL, @Search nvarchar(120) = NULL AS BEGIN SET NOCOUNT ON; SELECT * FROM dbo.IllustrationLibraryItems WHERE (@Category IS NULL OR Category = @Category) AND (@Status IS NULL OR Status = @Status) AND ( @Search IS NULL OR StableCode LIKE N'%' + @Search + N'%' OR DisplayTitle LIKE N'%' + @Search + N'%' OR ShortDescription LIKE N'%' + @Search + N'%' ) ORDER BY CASE Status WHEN N'Generating' THEN 1 WHEN N'Queued' THEN 2 WHEN N'Generated' THEN 3 WHEN N'Planned' THEN 4 WHEN N'Failed' THEN 5 WHEN N'Rejected' THEN 6 WHEN N'Approved' THEN 7 ELSE 8 END, UpdatedUtc DESC, IllustrationLibraryItemID DESC; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Summary AS BEGIN SET NOCOUNT ON; SELECT COUNT(1) AS TotalCount, ISNULL(SUM(CASE WHEN Status = N'Planned' THEN 1 ELSE 0 END), 0) AS PlannedCount, ISNULL(SUM(CASE WHEN Status = N'Queued' THEN 1 ELSE 0 END), 0) AS QueuedCount, ISNULL(SUM(CASE WHEN Status = N'Generating' THEN 1 ELSE 0 END), 0) AS GeneratingCount, ISNULL(SUM(CASE WHEN Status = N'Generated' THEN 1 ELSE 0 END), 0) AS GeneratedCount, ISNULL(SUM(CASE WHEN Status = N'Approved' THEN 1 ELSE 0 END), 0) AS ApprovedCount, ISNULL(SUM(CASE WHEN Status = N'Rejected' THEN 1 ELSE 0 END), 0) AS RejectedCount, ISNULL(SUM(CASE WHEN Status = N'Failed' THEN 1 ELSE 0 END), 0) AS FailedCount, ISNULL(SUM(CASE WHEN Status = N'Disabled' THEN 1 ELSE 0 END), 0) AS DisabledCount FROM dbo.IllustrationLibraryItems; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Get @IllustrationLibraryItemID int AS BEGIN SET NOCOUNT ON; SELECT * FROM dbo.IllustrationLibraryItems WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_UpsertPlanned @Category nvarchar(40), @StableCode nvarchar(120), @DisplayTitle nvarchar(200), @ShortDescription nvarchar(500) = NULL, @MetadataJson nvarchar(max) = NULL, @SpecificationJson nvarchar(max) = NULL AS BEGIN SET NOCOUNT ON; IF EXISTS ( SELECT 1 FROM dbo.IllustrationLibraryItems WHERE StableCode = @StableCode AND ParentItemID IS NULL AND IsActive = 1 AND Status IN (N'Planned', N'Queued', N'Generating', N'Generated', N'Approved') ) BEGIN SELECT * FROM dbo.IllustrationLibraryItems WHERE StableCode = @StableCode AND ParentItemID IS NULL AND IsActive = 1 AND Status IN (N'Planned', N'Queued', N'Generating', N'Generated', N'Approved'); RETURN; END; INSERT dbo.IllustrationLibraryItems (Category, StableCode, DisplayTitle, ShortDescription, MetadataJson, SpecificationJson, Status) VALUES (@Category, @StableCode, @DisplayTitle, @ShortDescription, @MetadataJson, @SpecificationJson, N'Planned'); SELECT * FROM dbo.IllustrationLibraryItems WHERE IllustrationLibraryItemID = SCOPE_IDENTITY(); END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Queue @IllustrationLibraryItemID int = NULL, @Category nvarchar(40) = NULL AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET Status = N'Queued', QueuedUtc = SYSUTCDATETIME(), UpdatedUtc = SYSUTCDATETIME(), LastError = NULL WHERE (@IllustrationLibraryItemID IS NULL OR IllustrationLibraryItemID = @IllustrationLibraryItemID) AND (@Category IS NULL OR Category = @Category) AND Status IN (N'Planned', N'Failed', N'Rejected') AND IsActive = 1; SELECT @@ROWCOUNT AS AffectedRows; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_ClaimNext AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; BEGIN TRANSACTION; DECLARE @Claimed TABLE (IllustrationLibraryItemID int NOT NULL); ;WITH nextItem AS ( SELECT TOP (1) * FROM dbo.IllustrationLibraryItems WITH (UPDLOCK, READPAST, ROWLOCK) WHERE Status = N'Queued' AND IsActive = 1 ORDER BY QueuedUtc, IllustrationLibraryItemID ) UPDATE nextItem SET Status = N'Generating', AttemptCount = AttemptCount + 1, StartedUtc = SYSUTCDATETIME(), UpdatedUtc = SYSUTCDATETIME() OUTPUT inserted.IllustrationLibraryItemID INTO @Claimed; SELECT item.* FROM dbo.IllustrationLibraryItems item INNER JOIN @Claimed claimed ON claimed.IllustrationLibraryItemID = item.IllustrationLibraryItemID; COMMIT TRANSACTION; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_MarkGenerated @IllustrationLibraryItemID int, @FilePath nvarchar(500), @ThumbnailPath nvarchar(500), @Width int, @Height int, @FileSizeBytes bigint, @MimeType nvarchar(100), @Provider nvarchar(80), @Model nvarchar(120), @PromptText nvarchar(max), @PromptTemplateVersion nvarchar(40), @ProviderRequestID nvarchar(160) = NULL AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET Status = N'Generated', FilePath = @FilePath, ThumbnailPath = @ThumbnailPath, Width = @Width, Height = @Height, FileSizeBytes = @FileSizeBytes, MimeType = @MimeType, Provider = @Provider, Model = @Model, PromptText = @PromptText, PromptTemplateVersion = @PromptTemplateVersion, ProviderRequestID = @ProviderRequestID, CompletedUtc = SYSUTCDATETIME(), UpdatedUtc = SYSUTCDATETIME(), LastError = NULL WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID AND Status = N'Generating'; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_MarkFailed @IllustrationLibraryItemID int, @LastError nvarchar(1000) AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET Status = N'Failed', LastError = @LastError, CompletedUtc = SYSUTCDATETIME(), UpdatedUtc = SYSUTCDATETIME() WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID AND Status = N'Generating'; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Approve @IllustrationLibraryItemID int, @ApprovedByUserID int AS BEGIN SET NOCOUNT ON; DECLARE @StableCode nvarchar(120); SELECT @StableCode = StableCode FROM dbo.IllustrationLibraryItems WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID; UPDATE dbo.IllustrationLibraryItems SET IsApproved = 0, Status = CASE WHEN Status = N'Approved' THEN N'Generated' ELSE Status END, UpdatedUtc = SYSUTCDATETIME() WHERE StableCode = @StableCode AND IllustrationLibraryItemID <> @IllustrationLibraryItemID AND Status = N'Approved'; UPDATE dbo.IllustrationLibraryItems SET Status = N'Approved', IsApproved = 1, ApprovedUtc = SYSUTCDATETIME(), ApprovedByUserID = @ApprovedByUserID, UpdatedUtc = SYSUTCDATETIME() WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID AND Status = N'Generated' AND FilePath IS NOT NULL; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Reject @IllustrationLibraryItemID int, @RejectionReason nvarchar(500) = NULL AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET Status = N'Rejected', IsApproved = 0, RejectionReason = @RejectionReason, UpdatedUtc = SYSUTCDATETIME() WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID AND Status IN (N'Generated', N'Approved'); END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_Disable @IllustrationLibraryItemID int AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET Status = N'Disabled', IsActive = 0, IsApproved = 0, UpdatedUtc = SYSUTCDATETIME() WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_UpdateMetadata @IllustrationLibraryItemID int, @DisplayTitle nvarchar(200), @ShortDescription nvarchar(500) = NULL, @MetadataJson nvarchar(max) = NULL, @AdminNotes nvarchar(1000) = NULL AS BEGIN SET NOCOUNT ON; UPDATE dbo.IllustrationLibraryItems SET DisplayTitle = @DisplayTitle, ShortDescription = @ShortDescription, MetadataJson = @MetadataJson, AdminNotes = @AdminNotes, UpdatedUtc = SYSUTCDATETIME() WHERE IllustrationLibraryItemID = @IllustrationLibraryItemID; END; GO CREATE OR ALTER PROCEDURE dbo.IllustrationLibraryItem_GetApproved AS BEGIN SET NOCOUNT ON; SELECT * FROM dbo.IllustrationLibraryItems WHERE Status = N'Approved' AND IsApproved = 1 AND IsActive = 1 AND FilePath IS NOT NULL ORDER BY StableCode, ApprovedUtc DESC; END; GO