feat(creator): Refactor Creator flow, implement book creation pipeline & versioning, and setup Docker staging
- Relocate dashboard routing to /creator and editor workspace to /creator/edit/{BookId}
- Implement CreateBookCommand and handler with transactional default chapter seeding
- Implement PublishBookVersionCommand and GetCreatorDashboardDataQuery
- Build CreatorDashboard modal and UI components with customized dark input styles
- Add run-stage.sh script to automate staging environment setup, database migrations, and health checks
- Update developer workflow rules in GEMINI.md
This commit is contained in:
@@ -25,6 +25,9 @@ public class AppDbContext : IdentityDbContext<NexusUser>
|
||||
public DbSet<QuizResult> QuizResults => Set<QuizResult>();
|
||||
public DbSet<SubscriptionPlan> SubscriptionPlans => Set<SubscriptionPlan>();
|
||||
public DbSet<Author> Authors => Set<Author>();
|
||||
public DbSet<Book> Books => Set<Book>();
|
||||
public DbSet<BookRevision> BookRevisions => Set<BookRevision>();
|
||||
public DbSet<Chapter> Chapters => Set<Chapter>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -114,6 +117,48 @@ public class AppDbContext : IdentityDbContext<NexusUser>
|
||||
entity.HasIndex(e => e.TenantId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Book>(entity =>
|
||||
{
|
||||
entity.HasKey(b => b.Id);
|
||||
entity.HasIndex(b => b.TenantId);
|
||||
entity.HasIndex(b => b.UserId);
|
||||
|
||||
entity.HasOne(e => e.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
entity.HasMany(b => b.Revisions)
|
||||
.WithOne(r => r.Book)
|
||||
.HasForeignKey(r => r.BookId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
entity.HasOne(b => b.CurrentDraftRevision)
|
||||
.WithMany()
|
||||
.HasForeignKey(b => b.CurrentDraftRevisionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
entity.HasOne(b => b.LivePublishedRevision)
|
||||
.WithMany()
|
||||
.HasForeignKey(b => b.LivePublishedRevisionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<BookRevision>(entity =>
|
||||
{
|
||||
entity.HasKey(r => r.Id);
|
||||
|
||||
entity.HasMany(r => r.Chapters)
|
||||
.WithOne(c => c.BookRevision)
|
||||
.HasForeignKey(c => c.BookRevisionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Chapter>(entity =>
|
||||
{
|
||||
entity.HasKey(c => c.Id);
|
||||
});
|
||||
|
||||
// Seed Subscription Plans with deterministic IDs
|
||||
modelBuilder.Entity<SubscriptionPlan>().HasData(
|
||||
new SubscriptionPlan { Id = 1, PlanName = SubscriptionPlan.FreeName, AITokenLimit = 5000, IsUnlimitedTokens = false, MonthlyPrice = 0m, StripeProductId = "prod_Free789" },
|
||||
|
||||
Reference in New Issue
Block a user