Rename Project concept to Novel across the stack
Renames the domain concept from Project to Novel throughout the backend (entities, DTOs, services, endpoints, ProjectAccessService/Permission, ProjectId foreign keys), MCP server (tool names and routes), and the React/Vite frontend (types, hooks, routes, components). Adds a new EF Core migration (RenameProjectToNovel) using RenameTable/RenameColumn to preserve existing data instead of dropping/recreating tables. Updates CLAUDE.md's structure section to reference Novels/ instead of Projects/.
This commit is contained in:
@@ -2,21 +2,21 @@ using Novelly.Api.Beats;
|
||||
using Novelly.Api.Chapters;
|
||||
using Novelly.Api.Characters;
|
||||
using Novelly.Api.Common;
|
||||
using Novelly.Api.Projects;
|
||||
using Novelly.Api.Novels;
|
||||
|
||||
namespace Novelly.Api.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class CharacterArcTests : ServiceTestFixture
|
||||
{
|
||||
private Guid _projectId;
|
||||
private Guid _novelId;
|
||||
private Guid _characterId;
|
||||
|
||||
protected override void OnSetUp()
|
||||
{
|
||||
_projectId = Projects.CreateAsync(new CreateProjectRequest("The Salt Road")).Result.Id;
|
||||
_novelId = Novels.CreateAsync(new CreateNovelRequest("The Salt Road")).Result.Id;
|
||||
_characterId = Characters.CreateAsync(
|
||||
_projectId,
|
||||
_novelId,
|
||||
new CreateCharacterRequest("Ines", CharacterRole.Protagonist, CharacterImportance.Main))
|
||||
.Result.Id;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task A_character_is_supporting_until_promoted()
|
||||
{
|
||||
var mara = await Characters.CreateAsync(_projectId, new CreateCharacterRequest("Mara"));
|
||||
var mara = await Characters.CreateAsync(_novelId, new CreateCharacterRequest("Mara"));
|
||||
|
||||
Assert.That(mara.Importance, Is.EqualTo(CharacterImportance.Supporting));
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task Importance_is_separate_from_the_part_a_character_plays()
|
||||
{
|
||||
var mentor = await Characters.CreateAsync(_projectId, new CreateCharacterRequest(
|
||||
var mentor = await Characters.CreateAsync(_novelId, new CreateCharacterRequest(
|
||||
"Anders", CharacterRole.Mentor, CharacterImportance.Main));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
@@ -50,11 +50,11 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task Main_characters_are_listed_before_supporting_ones()
|
||||
{
|
||||
await Characters.CreateAsync(_projectId, new CreateCharacterRequest("Zeno"));
|
||||
await Characters.CreateAsync(_novelId, new CreateCharacterRequest("Zeno"));
|
||||
await Characters.CreateAsync(
|
||||
_projectId, new CreateCharacterRequest("Mara", Importance: CharacterImportance.Main));
|
||||
_novelId, new CreateCharacterRequest("Mara", Importance: CharacterImportance.Main));
|
||||
|
||||
var listed = await Characters.ListAsync(_projectId);
|
||||
var listed = await Characters.ListAsync(_novelId);
|
||||
|
||||
Assert.That(
|
||||
listed.Select(c => c.Name),
|
||||
@@ -64,12 +64,12 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task Within_a_group_the_lead_comes_before_the_second_lead()
|
||||
{
|
||||
await Characters.CreateAsync(_projectId, new CreateCharacterRequest(
|
||||
await Characters.CreateAsync(_novelId, new CreateCharacterRequest(
|
||||
"Mara", CharacterRole.Deuteragonist, CharacterImportance.Main));
|
||||
await Characters.CreateAsync(_projectId, new CreateCharacterRequest(
|
||||
await Characters.CreateAsync(_novelId, new CreateCharacterRequest(
|
||||
"Anders", CharacterRole.Antagonist, CharacterImportance.Main));
|
||||
|
||||
var listed = await Characters.ListAsync(_projectId);
|
||||
var listed = await Characters.ListAsync(_novelId);
|
||||
|
||||
Assert.That(
|
||||
listed.Select(c => c.Name),
|
||||
@@ -127,7 +127,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task A_stage_pinned_to_a_chapter_resolves_that_chapter()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
|
||||
var stage = await Arcs.CreateAsync(
|
||||
_characterId, new CreateArcStageRequest("The map is wrong", ChapterId: chapter.Id));
|
||||
@@ -140,21 +140,21 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task A_stage_cannot_be_pinned_to_a_chapter_from_another_project()
|
||||
public async Task A_stage_cannot_be_pinned_to_a_chapter_from_another_novel()
|
||||
{
|
||||
var other = await Projects.CreateAsync(new CreateProjectRequest("Other Book"));
|
||||
var other = await Novels.CreateAsync(new CreateNovelRequest("Other Book"));
|
||||
var elsewhere = await Chapters.CreateAsync(other.Id, new CreateChapterRequest("Elsewhere"));
|
||||
|
||||
Assert.That(
|
||||
async () => await Arcs.CreateAsync(
|
||||
_characterId, new CreateArcStageRequest("A stage", ChapterId: elsewhere.Id)),
|
||||
Throws.TypeOf<InvalidOperationException>().With.Message.Contains("same project"));
|
||||
Throws.TypeOf<InvalidOperationException>().With.Message.Contains("same novel"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Deleting_a_chapter_unpins_an_arc_stage_rather_than_deleting_it()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
var stage = await Arcs.CreateAsync(
|
||||
_characterId, new CreateArcStageRequest("The map is wrong", ChapterId: chapter.Id));
|
||||
|
||||
@@ -188,9 +188,9 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task The_character_page_sees_every_beat_they_appear_in_across_the_book()
|
||||
{
|
||||
var second = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Second", Number: 2));
|
||||
var first = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("First", Number: 1));
|
||||
var mara = await Characters.CreateAsync(_projectId, new CreateCharacterRequest("Mara"));
|
||||
var second = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Second", Number: 2));
|
||||
var first = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("First", Number: 1));
|
||||
var mara = await Characters.CreateAsync(_novelId, new CreateCharacterRequest("Mara"));
|
||||
|
||||
await Beats.CreateAsync(second.Id, new CreateBeatRequest("She boards anyway", CharacterIds: [_characterId]));
|
||||
await Beats.CreateAsync(first.Id, new CreateBeatRequest("She finds the map", CharacterIds: [_characterId]));
|
||||
@@ -215,7 +215,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task An_arc_stage_groups_the_beats_assigned_to_it()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
var spoiled = await Beats.CreateAsync(chapter.Id, new CreateBeatRequest("Snaps at the crew", CharacterIds: [_characterId]));
|
||||
var humbled = await Beats.CreateAsync(chapter.Id, new CreateBeatRequest("Learns to swab a deck", CharacterIds: [_characterId]));
|
||||
var stage = await Arcs.CreateAsync(_characterId, new CreateArcStageRequest("Spoiled noble"));
|
||||
@@ -229,7 +229,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task Assigning_a_beat_to_a_stage_moves_it_out_of_the_characters_other_stage()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
var beat = await Beats.CreateAsync(chapter.Id, new CreateBeatRequest("Gets hurt", CharacterIds: [_characterId]));
|
||||
var early = await Arcs.CreateAsync(_characterId, new CreateArcStageRequest("Spoiled noble"));
|
||||
var later = await Arcs.CreateAsync(_characterId, new CreateArcStageRequest("Humbled"));
|
||||
@@ -250,8 +250,8 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task A_beat_can_only_be_grouped_into_a_stage_for_a_character_who_appears_in_it()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var mara = await Characters.CreateAsync(_projectId, new CreateCharacterRequest("Mara"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
var mara = await Characters.CreateAsync(_novelId, new CreateCharacterRequest("Mara"));
|
||||
var beat = await Beats.CreateAsync(chapter.Id, new CreateBeatRequest("Mara alone", CharacterIds: [mara.Id]));
|
||||
var stage = await Arcs.CreateAsync(_characterId, new CreateArcStageRequest("Spoiled noble"));
|
||||
|
||||
@@ -269,7 +269,7 @@ public class CharacterArcTests : ServiceTestFixture
|
||||
[Test]
|
||||
public async Task Clearing_a_stages_beats_with_an_empty_list_ungroups_them()
|
||||
{
|
||||
var chapter = await Chapters.CreateAsync(_projectId, new CreateChapterRequest("Landfall"));
|
||||
var chapter = await Chapters.CreateAsync(_novelId, new CreateChapterRequest("Landfall"));
|
||||
var beat = await Beats.CreateAsync(chapter.Id, new CreateBeatRequest("Snaps at the crew", CharacterIds: [_characterId]));
|
||||
var stage = await Arcs.CreateAsync(_characterId, new CreateArcStageRequest("Spoiled noble"));
|
||||
await Arcs.SetBeatsAsync(stage.Id, new SetArcStageBeatsRequest([beat!.Id]));
|
||||
|
||||
Reference in New Issue
Block a user