Add ChapterKind for front/back matter chapters

Chapters can now be marked FrontMatter/Body/BackMatter. Number stays
the manuscript sort key for every chapter; the author-facing display
number is now computed per-request as the chapter's ordinal among
Body chapters only, so a foreword or afterword no longer shifts the
numbering of the rest of the book. Surfaced through the API, agent
toolset, and import toolset.
This commit is contained in:
James Wampler
2026-08-19 17:54:20 -07:00
parent 71953220aa
commit ef5260a111
12 changed files with 1526 additions and 27 deletions
@@ -73,6 +73,7 @@ public class ChapterService(
NovelId = novelId,
Title = request.Title,
Number = request.Number ?? await NextChapterNumberAsync(novelId, ct),
Kind = request.Kind,
Summary = request.Summary,
Notes = request.Notes,
Status = request.Status,
@@ -116,6 +117,7 @@ public class ChapterService(
chapter.Title = Patch.Apply(chapter.Title, request.Title) ?? chapter.Title;
chapter.Number = request.Number ?? chapter.Number;
chapter.Kind = request.Kind ?? chapter.Kind;
chapter.Summary = Patch.Apply(chapter.Summary, request.Summary);
chapter.Notes = Patch.Apply(chapter.Notes, request.Notes);
chapter.Status = request.Status ?? chapter.Status;
@@ -166,6 +168,15 @@ public class ChapterService(
return true;
}
public async Task<int?> DisplayNumberAsync(Chapter chapter, CancellationToken ct = default)
{
if (chapter.Kind != ChapterKind.Body)
return null;
return await db.Chapters.CountAsync(
c => c.NovelId == chapter.NovelId && c.Kind == ChapterKind.Body && c.Number <= chapter.Number, ct);
}
private async Task<int> NextChapterNumberAsync(Guid novelId, CancellationToken ct)
{
logger.LogDebug("Computing next chapter number for novel {NovelId}", novelId);