Surface arcs, character beats and open questions in the web client
The character page gains three sections under the dossier: the arc as an editable ordered table with each stage pinnable to a chapter, every beat the character appears in across the book (each row linking into that chapter's outline), and the character's open questions. The sidebar groups main characters above supporting ones, and both the sheet and the add dialog let you set importance. The arc section shows for main characters, and also for supporting ones that already have stages — demoting someone should not hide work they thought they had lost. The outline page gains a notes section and an open-questions section at the bottom. Beat rows are now anchored so the character page can link straight to a row. Raising a question from either page attaches it to what that page is about, and the section hides the association it is already scoped to rather than repeating "Landfall" on every row. Also fixes an ordering wart the browser run exposed: both CharacterRole and CharacterImportance are stored as text, so ordering them in SQL ordered the spelling — "Deuteragonist" beat "Protagonist" and the sidebar put the second lead above the character the book is about. Listing now sorts after materialising, which uses the enums' declaration order. The test for it was checked both ways: it fails on the SQL ordering and passes on the fix. 73 tests pass, the web client builds and lints clean. Driven in a browser end to end: resolving a question with "also add to notes" drops it off the open list and appends the decision under the chapter's existing note, "show resolved" brings it back with a Reopen button, and a beat link on the character page lands on the right chapter outline at that beat's anchor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S56bfZMGe1hnhpWP4CjjNw
This commit is contained in:
co-authored by
Claude Opus 5
parent
0358667679
commit
4f396bb5f9
@@ -65,7 +65,7 @@ and everything else keeps working.
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
dotnet test # 44 tests
|
||||
dotnet test # 73 tests
|
||||
cd src/Novelly.Web && npm run build # typecheck + bundle
|
||||
```
|
||||
|
||||
@@ -98,10 +98,12 @@ out of `appsettings.json` and use user-secrets or the environment.
|
||||
## The data model
|
||||
|
||||
```
|
||||
Project ──┬── Character ── CharacterRelationship
|
||||
Project ──┬── Character ──┬── CharacterRelationship
|
||||
│ └── CharacterArcStage (the arc: flat, ordered)
|
||||
├── Chapter ──┬── Beat (the outline: flat, ordered)
|
||||
│ └── Scene (the prose)
|
||||
├── Tag (applied to characters, chapters and beats)
|
||||
├── OpenQuestion (attached to a chapter and/or a character)
|
||||
└── AgentConversation ── AgentMessage
|
||||
```
|
||||
|
||||
@@ -124,6 +126,29 @@ is for working out what happens, and a scene is where you write it. A beat's `Sc
|
||||
the optional link between them, and it is nullable in both directions — deleting a scene
|
||||
ungroups its beats rather than deleting the plan.
|
||||
|
||||
**Main characters carry the book; supporting characters hold it up.** A character's
|
||||
`Importance` (`Main` or `Supporting`) is separate from their `Role` — role is the part they
|
||||
play in the story, importance is how much of it they take, and a mentor can be either.
|
||||
Characters start supporting and get promoted. The two together drive the ordering, so the
|
||||
protagonist is always the first name on the list.
|
||||
|
||||
**A main character's arc is a table, not a paragraph.** `ArcSummary` still holds the
|
||||
sentence version; `CharacterArcStage` breaks the same change into ordered steps, each
|
||||
optionally pinned to the chapter it lands in. It is the same flat-and-ordered shape as the
|
||||
beat table, for the same reason. Nothing refuses an arc on a supporting character —
|
||||
demoting someone should not delete their work.
|
||||
|
||||
**The character page reads the outlines back.** `GET /api/characters/{id}/beats` returns
|
||||
every beat a character appears in, in manuscript order, each carrying its chapter so the
|
||||
page links straight into that chapter's outline. It is the dossier's reality check: what
|
||||
they actually do on the page, as against what the sheet claims about them.
|
||||
|
||||
**Open questions are what you have not decided.** A question hangs off a chapter outline, a
|
||||
character, both, or neither. It can be resolved, reopened or deleted, and resolving can
|
||||
append the decision to the notes of whatever it was attached to — so a settled question ends
|
||||
up where you re-read it rather than in a list you have stopped looking at. Resolved
|
||||
questions drop off the list unless you ask for them.
|
||||
|
||||
**Tags cross-reference the book.** A tag is scoped to one project, unique by name
|
||||
(case-insensitively), and can be attached to any character, chapter or beat. Applying an
|
||||
unknown tag by name creates it, so tagging is one action rather than two. `GET
|
||||
@@ -134,8 +159,9 @@ motif or a thread across all three kinds at once.
|
||||
|
||||
`NovelAgentService` runs the tool-use loop: it calls the Messages API, executes any tools
|
||||
Claude asks for, feeds every result back in a single user turn, and repeats until Claude
|
||||
stops asking. It has 18 tools covering the brief, characters, chapter outlines (beats), scenes and
|
||||
tags — all of them going through the same application services the REST API uses.
|
||||
stops asking. It has 29 tools covering the brief, characters and their arcs, chapter outlines
|
||||
(beats), scenes, tags and open questions — all of them going through the same application
|
||||
services the REST API uses.
|
||||
|
||||
A few deliberate choices worth knowing about:
|
||||
|
||||
@@ -153,7 +179,7 @@ A few deliberate choices worth knowing about:
|
||||
|
||||
## The MCP server
|
||||
|
||||
A stdio MCP server exposing 26 tools over the same REST API. It holds no domain logic of
|
||||
A stdio MCP server exposing 38 tools over the same REST API. It holds no domain logic of
|
||||
its own — it is a second front end, not a second implementation.
|
||||
|
||||
Build it, then point your MCP client at the produced binary:
|
||||
@@ -190,6 +216,8 @@ rather than failing opaquely.
|
||||
| Beats | `GET\|POST /api/chapters/{id}/beats`, `POST /api/chapters/{id}/beats/reorder`, `GET\|PATCH\|DELETE /api/beats/{id}` |
|
||||
| Scenes | `GET\|POST /api/chapters/{id}/scenes`, `GET\|PATCH\|DELETE /api/scenes/{id}` |
|
||||
| Tags | `GET\|POST /api/projects/{id}/tags`, `GET /api/tags/{id}/references`, `PATCH\|DELETE /api/tags/{id}` |
|
||||
| Arcs | `GET\|POST /api/characters/{id}/arc`, `POST /api/characters/{id}/arc/reorder`, `GET\|PATCH\|DELETE /api/arc-stages/{id}` |
|
||||
| Questions | `GET\|POST /api/projects/{id}/questions`, `GET\|PATCH\|DELETE /api/questions/{id}`, `POST /api/questions/{id}/resolve`, `POST /api/questions/{id}/reopen` |
|
||||
| Agent | `GET /api/projects/{id}/agent/conversations`, `POST /api/projects/{id}/agent/messages`, `GET\|DELETE /api/conversations/{id}` |
|
||||
|
||||
`PATCH` bodies are partial: an omitted field is left alone, an empty string clears it. A
|
||||
|
||||
Reference in New Issue
Block a user