Add outline import feature; drop Dto naming, map entities at the API boundary
Services now return entities; endpoints (and the agent toolsets) map to *Response records instead of services building wire DTOs themselves. Also brings in the outline-import agent, MCP tool, ledger and web dialog that were already in progress on disk.
This commit is contained in:
@@ -3,6 +3,7 @@ using Novelly.Api.Agent;
|
||||
using Novelly.Api.Beats;
|
||||
using Novelly.Api.Chapters;
|
||||
using Novelly.Api.Characters;
|
||||
using Novelly.Api.Imports;
|
||||
using Novelly.Api.Projects;
|
||||
using Novelly.Api.Questions;
|
||||
using Novelly.Api.Scenes;
|
||||
@@ -27,6 +28,7 @@ public interface INovelDbContext
|
||||
DbSet<OpenQuestion> OpenQuestions { get; }
|
||||
DbSet<AgentConversation> Conversations { get; }
|
||||
DbSet<AgentMessage> AgentMessages { get; }
|
||||
DbSet<ImportJob> ImportJobs { get; }
|
||||
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,832 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Novelly.Api.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Novelly.Api.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(NovelDbContext))]
|
||||
[Migration("20260807001613_AddImportJobs")]
|
||||
partial class AddImportJobs
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.10");
|
||||
|
||||
modelBuilder.Entity("BeatTag", b =>
|
||||
{
|
||||
b.Property<Guid>("BeatsId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("TagsId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("BeatsId", "TagsId");
|
||||
|
||||
b.HasIndex("TagsId");
|
||||
|
||||
b.ToTable("BeatTags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ChapterTag", b =>
|
||||
{
|
||||
b.Property<Guid>("ChaptersId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("TagsId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ChaptersId", "TagsId");
|
||||
|
||||
b.HasIndex("TagsId");
|
||||
|
||||
b.ToTable("ChapterTags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CharacterTag", b =>
|
||||
{
|
||||
b.Property<Guid>("CharactersId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("TagsId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("CharactersId", "TagsId");
|
||||
|
||||
b.HasIndex("TagsId");
|
||||
|
||||
b.ToTable("CharacterTags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Agent.AgentConversation", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("Conversations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Agent.AgentMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ConversationId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.IsRequired()
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Sequence")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ToolCallsJson")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ConversationId", "Sequence")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AgentMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Beats.Beat", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ChapterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("CharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("SceneId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("WhatHappened")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("WhatsNext")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CharacterId");
|
||||
|
||||
b.HasIndex("SceneId");
|
||||
|
||||
b.HasIndex("ChapterId", "SortOrder");
|
||||
|
||||
b.ToTable("Beats");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Chapters.Chapter", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Number")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("PovCharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Setting")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Summary")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("TargetWordCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(300)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PovCharacterId");
|
||||
|
||||
b.HasIndex("ProjectId", "Number");
|
||||
|
||||
b.ToTable("Chapters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.Character", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Age")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Appearance")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ArcSummary")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Backstory")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ExternalConflict")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Importance")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InternalConflict")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Need")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Occupation")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Personality")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Pronouns")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Voice")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Want")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("Characters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.CharacterArcStage", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("ChapterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChapterId");
|
||||
|
||||
b.HasIndex("CharacterId", "SortOrder");
|
||||
|
||||
b.ToTable("CharacterArcStages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.CharacterRelationship", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RelatedCharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RelationshipType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CharacterId");
|
||||
|
||||
b.HasIndex("RelatedCharacterId");
|
||||
|
||||
b.ToTable("CharacterRelationships");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Imports.ImportJob", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ChaptersCompleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ChaptersTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SourceRoot")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("StatusMessage")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SourceRoot");
|
||||
|
||||
b.ToTable("ImportJobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Projects.Project", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Author")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Genre")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Logline")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Synopsis")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("TargetWordCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(300)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Projects");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Questions.OpenQuestion", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("ChapterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("CharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Detail")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Question")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Resolution")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long?>("ResolvedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChapterId");
|
||||
|
||||
b.HasIndex("CharacterId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("OpenQuestions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Scenes.Scene", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ChapterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Conflict")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Goal")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Outcome")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("PovCharacterId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Prose")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Summary")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(300)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WordCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PovCharacterId");
|
||||
|
||||
b.HasIndex("ChapterId", "SortOrder");
|
||||
|
||||
b.ToTable("Scenes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Tags.Tag", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Color")
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProjectId", "Name")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BeatTag", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Beats.Beat", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("BeatsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Tags.Tag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ChapterTag", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Chapters.Chapter", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("ChaptersId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Tags.Tag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CharacterTag", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Characters.Character", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CharactersId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Tags.Tag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Agent.AgentConversation", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Projects.Project", "Project")
|
||||
.WithMany("Conversations")
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Agent.AgentMessage", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Agent.AgentConversation", "Conversation")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("ConversationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Conversation");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Beats.Beat", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Chapters.Chapter", "Chapter")
|
||||
.WithMany("Beats")
|
||||
.HasForeignKey("ChapterId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Characters.Character", "Character")
|
||||
.WithMany()
|
||||
.HasForeignKey("CharacterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Novelly.Api.Scenes.Scene", "Scene")
|
||||
.WithMany()
|
||||
.HasForeignKey("SceneId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Chapter");
|
||||
|
||||
b.Navigation("Character");
|
||||
|
||||
b.Navigation("Scene");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Chapters.Chapter", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Characters.Character", "PovCharacter")
|
||||
.WithMany()
|
||||
.HasForeignKey("PovCharacterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Novelly.Api.Projects.Project", "Project")
|
||||
.WithMany("Chapters")
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("PovCharacter");
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.Character", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Projects.Project", "Project")
|
||||
.WithMany("Characters")
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.CharacterArcStage", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Chapters.Chapter", "Chapter")
|
||||
.WithMany()
|
||||
.HasForeignKey("ChapterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Novelly.Api.Characters.Character", "Character")
|
||||
.WithMany("ArcStages")
|
||||
.HasForeignKey("CharacterId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Chapter");
|
||||
|
||||
b.Navigation("Character");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.CharacterRelationship", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Characters.Character", "Character")
|
||||
.WithMany("Relationships")
|
||||
.HasForeignKey("CharacterId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Characters.Character", "RelatedCharacter")
|
||||
.WithMany()
|
||||
.HasForeignKey("RelatedCharacterId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Character");
|
||||
|
||||
b.Navigation("RelatedCharacter");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Questions.OpenQuestion", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Chapters.Chapter", "Chapter")
|
||||
.WithMany()
|
||||
.HasForeignKey("ChapterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Novelly.Api.Characters.Character", "Character")
|
||||
.WithMany()
|
||||
.HasForeignKey("CharacterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Novelly.Api.Projects.Project", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Chapter");
|
||||
|
||||
b.Navigation("Character");
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Scenes.Scene", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Chapters.Chapter", "Chapter")
|
||||
.WithMany("Scenes")
|
||||
.HasForeignKey("ChapterId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Novelly.Api.Characters.Character", "PovCharacter")
|
||||
.WithMany()
|
||||
.HasForeignKey("PovCharacterId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Chapter");
|
||||
|
||||
b.Navigation("PovCharacter");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Tags.Tag", b =>
|
||||
{
|
||||
b.HasOne("Novelly.Api.Projects.Project", "Project")
|
||||
.WithMany("Tags")
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Agent.AgentConversation", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Chapters.Chapter", b =>
|
||||
{
|
||||
b.Navigation("Beats");
|
||||
|
||||
b.Navigation("Scenes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Characters.Character", b =>
|
||||
{
|
||||
b.Navigation("ArcStages");
|
||||
|
||||
b.Navigation("Relationships");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Projects.Project", b =>
|
||||
{
|
||||
b.Navigation("Chapters");
|
||||
|
||||
b.Navigation("Characters");
|
||||
|
||||
b.Navigation("Conversations");
|
||||
|
||||
b.Navigation("Tags");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Novelly.Api.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddImportJobs : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ImportJobs",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
SourceRoot = table.Column<string>(type: "TEXT", maxLength: 1000, nullable: false),
|
||||
ProjectId = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
Status = table.Column<string>(type: "TEXT", maxLength: 16, nullable: false),
|
||||
StatusMessage = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ChaptersCompleted = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ChaptersTotal = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CreatedAt = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
UpdatedAt = table.Column<long>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ImportJobs", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ImportJobs_SourceRoot",
|
||||
table: "ImportJobs",
|
||||
column: "SourceRoot");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ImportJobs");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,6 +365,47 @@ namespace Novelly.Api.Data.Migrations
|
||||
b.ToTable("CharacterRelationships");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Imports.ImportJob", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ChaptersCompleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ChaptersTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("CreatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SourceRoot")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("StatusMessage")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("UpdatedAt")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SourceRoot");
|
||||
|
||||
b.ToTable("ImportJobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Novelly.Api.Projects.Project", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
||||
@@ -4,6 +4,7 @@ using Novelly.Api.Agent;
|
||||
using Novelly.Api.Beats;
|
||||
using Novelly.Api.Chapters;
|
||||
using Novelly.Api.Characters;
|
||||
using Novelly.Api.Imports;
|
||||
using Novelly.Api.Projects;
|
||||
using Novelly.Api.Questions;
|
||||
using Novelly.Api.Scenes;
|
||||
@@ -36,6 +37,7 @@ public class NovelDbContext(DbContextOptions<NovelDbContext> options)
|
||||
public DbSet<OpenQuestion> OpenQuestions => Set<OpenQuestion>();
|
||||
public DbSet<AgentConversation> Conversations => Set<AgentConversation>();
|
||||
public DbSet<AgentMessage> AgentMessages => Set<AgentMessage>();
|
||||
public DbSet<ImportJob> ImportJobs => Set<ImportJob>();
|
||||
|
||||
Task<int> INovelDbContext.SaveChangesAsync(CancellationToken cancellationToken) =>
|
||||
base.SaveChangesAsync(cancellationToken);
|
||||
@@ -183,5 +185,15 @@ public class NovelDbContext(DbContextOptions<NovelDbContext> options)
|
||||
entity.Property(m => m.Role).HasConversion<string>().HasMaxLength(16);
|
||||
entity.HasIndex(m => new { m.ConversationId, m.Sequence }).IsUnique();
|
||||
});
|
||||
|
||||
builder.Entity<ImportJob>(entity =>
|
||||
{
|
||||
entity.Property(j => j.SourceRoot).IsRequired().HasMaxLength(1000);
|
||||
entity.Property(j => j.Status).HasConversion<string>().HasMaxLength(16);
|
||||
|
||||
// No FK to Project: a job outlives the project it created, including the
|
||||
// force-restart path where that project is deleted out from under it.
|
||||
entity.HasIndex(j => j.SourceRoot);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user