Files
novelly/src/Novelly.Api/Data/NovelDbContext.cs
T
James Wampler 71953220aa
CI / build-and-push (push) Successful in 52s
CI / deploy (push) Successful in 9s
Add GitHub-style activity contribution graph
Record create/update/delete events across novel content (chapters, beats,
characters, arc stages, tags, locations, questions) into an append-only
ActivityEvent log, aggregate by UTC day, and surface as a heatmap on the
novels list and each novel's dashboard. Backfills history from existing
CreatedAt timestamps on first boot after the migration.
2026-08-19 17:39:13 -07:00

71 lines
3.0 KiB
C#

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.EntityFrameworkCore;
using Novelly.Api.Activity;
using Novelly.Api.Agent;
using Novelly.Api.Beats;
using Novelly.Api.Chapters;
using Novelly.Api.Characters;
using Novelly.Api.Genres;
using Novelly.Api.Imports;
using Novelly.Api.Locations;
using Novelly.Api.Novels;
using Novelly.Api.Questions;
using Novelly.Api.Tags;
using Novelly.Api.Users;
namespace Novelly.Api.Data;
internal class UtcTicksConverter() : ValueConverter<DateTimeOffset, long>(value => value.UtcTicks, ticks => new DateTimeOffset(ticks, TimeSpan.Zero));
public class NovelDbContext(DbContextOptions<NovelDbContext> options) : IdentityUserContext<NovellyUser, Guid>(options), INovelDbContext
{
public DbSet<Novel> Novels => Set<Novel>();
public DbSet<Character> Characters => Set<Character>();
public DbSet<CharacterRelationship> CharacterRelationships => Set<CharacterRelationship>();
public DbSet<CharacterArcStage> CharacterArcStages => Set<CharacterArcStage>();
public DbSet<Beat> Beats => Set<Beat>();
public DbSet<Tag> Tags => Set<Tag>();
public DbSet<Location> Locations => Set<Location>();
public DbSet<Chapter> Chapters => Set<Chapter>();
public DbSet<OpenQuestion> OpenQuestions => Set<OpenQuestion>();
public DbSet<AgentConversation> Conversations => Set<AgentConversation>();
public DbSet<AgentMessage> AgentMessages => Set<AgentMessage>();
public DbSet<ImportJob> ImportJobs => Set<ImportJob>();
public DbSet<Genre> Genres => Set<Genre>();
public DbSet<NovelMember> NovelMembers => Set<NovelMember>();
public DbSet<ActivityEvent> ActivityEvents => Set<ActivityEvent>();
Task<int> INovelDbContext.SaveChangesAsync(CancellationToken cancellationToken) => base.SaveChangesAsync(cancellationToken);
protected override void ConfigureConventions(ModelConfigurationBuilder builder) => builder.Properties<DateTimeOffset>().HaveConversion<UtcTicksConverter>();
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(NovelDbContext).Assembly);
}
}
public interface INovelDbContext
{
DbSet<Novel> Novels { get; }
DbSet<Character> Characters { get; }
DbSet<CharacterRelationship> CharacterRelationships { get; }
DbSet<CharacterArcStage> CharacterArcStages { get; }
DbSet<Beat> Beats { get; }
DbSet<Tag> Tags { get; }
DbSet<Location> Locations { get; }
DbSet<Chapter> Chapters { get; }
DbSet<OpenQuestion> OpenQuestions { get; }
DbSet<AgentConversation> Conversations { get; }
DbSet<AgentMessage> AgentMessages { get; }
DbSet<ImportJob> ImportJobs { get; }
DbSet<Genre> Genres { get; }
DbSet<NovellyUser> Users { get; }
DbSet<NovelMember> NovelMembers { get; }
DbSet<ActivityEvent> ActivityEvents { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}