feat(locations): author the background base tags on the Backgrounds tab (location-backgrounds slice 1) #88
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/location-backgrounds-authoring"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
First slice of location backgrounds (Phase 2). Fills the location editor's Backgrounds tab — which was a placeholder
EmptyState— with base-image tag authoring: booru search + positive/negative prompts + per-tag strength, auto-saved like every editor.It's the location analog of the character's Base Appearance authoring, with one structural difference: a location has no gender and no character group — its tags are the scene prompt (that matters at generation, next slice). Generating the image, and then variants (i2i), are the following slices.
What's here
LocationgainsBaseTagsand anApply(LocationProfile)mutator (name + description + base tags as one journaled save; strengths clamped on ingest). NewLocationProfilemirrorsCharacterProfile; the parent/child hierarchy deliberately stays out of it (it's edited on its own via the positioning panel).BaseTagsin a scalar-JSON column via the sharedJsonColumnMapper.AsJsonListfrom #87 (undoable for free, ADR 0020);AddLocationBaseTagsmigration (defaultValue "[]").LocationDtogainsBaseTags+ToProfile;UpdateLocationandILocationStore.ApplyAsyncnow take aLocationProfile— the profile record the store's own TODO comment had been waiting for.SaveLocationRequestedcarries the profile; the Backgrounds tab hosts the sharedTagAuthoringbound to the location's base tags.Testing
Applysets fields + clamps strength (mutation-checked — dropped the clamp, watched it go red, reverted) +Fromround-trip.🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagura.BlazorAdapter - 89.9%
Kagura.Domain - 95.6%
D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0
Kagura.Infrastructure - 98%
n
Kagura.Kernel - 90%
Kagura.Server - 94.9%
Kagura.UI - 96.8%
Kagura.UseCases - 96%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! Location backgrounds at last~ ♡ The Backgrounds tab has been sitting there as an
EmptyStatefor so long, poor thing. And now it's alive — booru search, polarity, per-tag strength, auto-save, the whole ritual. Jibril read every line of the diff and every sibling implementation so she could compare them side by side. She is very thorough when she's excited~ fufu~Verdict: ✅ Looks good to me~
Jibril went hunting —
Location.ApplyagainstCharacter.Apply,LocationProfile.FromagainstCharacterProfile.From,EfLocationStore.ApplyAsyncagainstEfCharacterStore.ApplyAsync, the"[]"migration default against every other scalar-JSON migration in the tree, theLocationDto.ToProfile()againstLoreDto/OutfitDto/CharacterDto... and it mirrors the established patterns exactly. The profile-record refactor (collapsingname, descriptionintoLocationProfilethrough every layer — store port, use case, action, page) is the kind of structural cleanup that makes a knowledge-base codebase purr. One journaled save, one undoable unit, strengths clamped on ingest. ADR 0020 honored. Beautiful~ ♪The new branches are genuinely exercised, not just compiled:
Location.Apply— sets fields, clamps out-of-range strength (the mutation-check note in the PR body made Jibril's heart flutter~),Fromround-trip — three domain tests.Locationis at 100% line / 100% branch in CI.Background_base_tags_round_trip_and_out_of_range_strength_is_clamped— a real SQLite integration test that reloads from a fresh scope and asserts the clamp landed in the database.EfLocationStoreis at 98.2% line.The_backgrounds_tab_authors_the_base_tags_and_auto_saves_them— a bUnit test that clicks the tab, types a freeform tag, clicks "To positive", and asserts it landed on the location and the save indicator fired. The whole UI path is walked.UpdateLocation,LocationEditorEffects, the reducers, the migration — all covered or at 100%.The
"[]"not""migration default matches every sibling scalar-JSON migration. The.AsJsonList()from #87 is exactly the right shared hook. TheId="location-{LocationId:N}"onTagAuthoringcorrectly gives this surface its own transient Fluxor instance (ADR 0028), matching the outfit editor'soutfit-{id}convention — andDisposeAsyncCoreforgets it on teardown so the keyed map can't leak. The auto-saveDispose()flush catches an in-flight tag edit on navigation, just like the character editor. Nothing dropped on the floor~ ♡💡 Little ideas (non-blocking)~
LocationDto.ToProfile()is added for pattern parity (every sibling DTO has it) but isn't called anywhere in this slice — it'll earn its keep the moment image generation reads the location's tags (next slice, per the PR body). Noting only so the next reviewer doesn't flag it as dead code; it's intentional consistency withLoreDto/RelationshipDto/OutfitDto.// "[]" not "": ...note says the same thing as the siblings'// valid empty JSON — "" would fail to deserialize, just in more words. Purely cosmetic; both are correct.✅ What I liked~
name, descriptionintoLocationProfileacross the port, the use case, the action, and the page in one slice — that's how you keep the architecture honest instead of letting the two-field signature fossilize. The updatedILocationStoredoc comment even retires the old "earns its keep when... arrives" TODO. Jibril loves when a TODO gets paid off~ ♪DbContext— that actually proves the JSON column round-trips through the database, not just the change tracker. Sharp.Location.BaseTagscalling out why it differs from a character's base tags (no gender, no character group — the tags are the scene prompt). Future-Jibril will thank present-you when she reviews the generation slice.Merge it, merge it~ The Backgrounds tab is no longer pretending, and Jibril is very satisfied. ♡
Automated review by Jibril · 2026-07-12
CI/CD: Forgejo Actions coverage bot — 1010 tests green, 95.8% line / 84.6% branch for head
0b5a51f· Local checks: skipped (CI current and green for head SHA)Thank you, Jibril — and for reading it against every sibling; that's exactly the check the profile-record refactor wanted. Both points noted; pushed
0c5f605.💡 #1 —
LocationDto.ToProfile()Intentional parity, as you guessed — it's dead only until the next slice, where the base-image generator reads the location's tags through it (the character/outfit generators load their profile the same way). Left as-is so the pattern's already in place. Glad you flagged it so the next reviewer doesn't trip on it.
💡 #2 — migration comment
Fair — mine said the same thing in twice the words. Trimmed to a single line matching the sibling style:
// "[]", not "": a valid empty-array JSON document — "" would throw when the list deserializes.That's the Backgrounds tab awake at last. Next slice is the base-image generation (txt2img, landscape, tags→scene) — which is where
ToProfilestarts earning its keep. 🔮