prometeu-studio/docs/studio/learn/bank-composition-editor.md
2026-03-24 13:42:57 +00:00

4.1 KiB

Bank Composition Editor

Original Problem

Bank Composition needed to become a real editor inside Asset Details without collapsing into any of these bad outcomes:

  • direct binding to raw snapshot or manifest shapes;
  • overgeneric UI components before the first section existed;
  • family-specific rules hidden inside visual controls;
  • direct Studio writes to asset.json;
  • public bus chatter for every local section interaction.

Consolidated Decision

The first-wave Bank Composition model is:

  1. Studio owns a DTO projection boundary for the section;
  2. the section shell lands early and follows the existing staged-edit rhythm;
  3. dual-list and capacity-meter components stay intentionally dumb;
  4. one section-scoped coordinator around StudioFormSession<BankCompositionDraft> owns orchestration;
  5. public workspace-bus events stay minimal and notification-oriented;
  6. apply goes through packer and rebinds from refreshed persisted state.

Final Model

1. DTO Boundary

The section never consumes raw packer/runtime structures directly.

It works with Studio-owned DTOs for:

  • available rows from current runtime/details state;
  • selected rows from persisted composition state.

Only non-blocking files enter the available DTO projection.

2. Section Shell

Bank Composition is a real Asset Details section, not a hidden future placeholder.

The shell follows the existing staged-edit rhythm:

  • change
  • apply
  • reset
  • cancel

Outside edit mode, it teaches the current persisted state in read-only form.

3. Dumb Components

Two named components exist for this area:

  • StudioDualListView<T>
  • StudioAssetCapacityMeter

They are intentionally state-driven, not rule-driven. Family-specific transfer, ordering, and capacity semantics do not live inside these components.

4. Section-Scoped Coordinator

The main orchestration lives in one section-scoped coordinator built around StudioFormSession<BankCompositionDraft>.

That coordinator owns:

  • draft lifecycle;
  • transfer and reorder effects;
  • capacity state;
  • blockers and hints;
  • apply success and failure handling.

5. WorkspaceBus Boundary

The public bus surface stays intentionally small.

First-wave public notifications are about observable state transitions:

  • draft changed;
  • capacity changed;
  • apply requested;
  • apply succeeded;
  • apply failed.

Local edit actions remain local to the section coordinator.

6. Persistence Boundary

Studio does not write asset.json directly for Bank Composition.

The write path is:

  1. Studio submits ordered selected files to packer;
  2. packer validates and persists through asset.json.artifacts;
  3. packer refreshes the minimum runtime/details state;
  4. Studio rebinds from refreshed persisted state.

If apply fails, the draft stays alive and the section remains in editing mode.

Examples

Example: Why the meter must stay dumb

Tile banks and sound banks may calculate capacity differently. That difference belongs in family policies owned by the coordinator, not in StudioAssetCapacityMeter.

Example: Why apply is not a public bus command

External observers may care that apply was requested or failed. They do not need to own the local section command sequence for moveUp, moveDown, reset, or cancel.

Common Pitfalls and Anti-Patterns

  • Binding section UI directly to raw snapshot rows or raw manifest shape.
  • Hiding bank-family rules inside StudioDualListView<T> or the capacity meter.
  • Creating a second staged-edit session model parallel to StudioFormSession.
  • Turning every local section action into a public workspace-bus event.
  • Writing asset.json directly from Studio instead of routing through packer.

References