Frontend Bean Scene Authoring
This guide explains the advanced Zova workflow for creating a new frontend bean scene.
This is not the same as creating one more bean inside an existing scene such as api, model, service, controller, or render.
For ordinary bean creation inside an existing scene, use the existing CLI workflow documented in Frontend CLI and the scene-specific frontend guides. This page is for framework extension work where you need to define a new scene contract.
When you need this guide
Use this guide when you need to extend the frontend bean system itself, for example:
- define a new decorator such as
@Something() - teach
:create:beanhow to scaffold that scene - add new scene-level metadata behavior
- decide the scene’s container scope
- decide whether the scene should be isolated under its own folder
If you only need a new api, model, or service bean, you do not need this page.
Mental model
In Zova, a bean scene is not only a naming family. It also helps define runtime resolution behavior.
A frontend scene usually determines:
- which decorator marks the class
- which container scope the scene uses
- whether generated files go to
src/beanorsrc/<scene>/ - whether generated bean typing lands in a general or local record surface
- whether scene-specific metadata generation runs
This is why frontend scene authoring must explain both scene name and container scope together.
The smallest built-in patterns
Representative built-in patterns are thin wrappers over createBeanDecorator(...).
Examples:
export function Bean(): ClassDecorator {
return createBeanDecorator('bean', 'ctx');
}
export function Service(): ClassDecorator {
return createBeanDecorator('service', 'ctx');
}
export function Tool(): ClassDecorator {
return createBeanDecorator('tool', 'app');
}2
3
4
5
6
7
8
9
10
11
Some scenes also carry decorator options:
export function Model<T extends IDecoratorModelOptions>(options?: T): ClassDecorator {
return createBeanDecorator('model', 'ctx', true, options);
}2
3
This shows the first scene-authoring contract clearly:
- give the scene a stable scene name
- choose the container scope deliberately
- optionally support decorator options
The frontend authoring surfaces
A new frontend bean scene usually touches five surfaces.
1. Decorator surface
Define the scene decorator and export it from the owning module.
Representative built-in decorators include:
@Bean()->ctx@Service()->ctx@Tool()->app@Data()->new@Api()->app@Model()->ctx
This container choice is part of the scene contract, not only an implementation detail.
2. Scene typing surface
Register the scene through declaration merging.
Representative pattern:
declare module 'zova' {
export interface IBeanSceneRecord {
api: never;
}
}2
3
4
5
Some scenes also extend module-specific type surfaces. For example, model contributes to ConfigOnions and to a service-like onion options surface in its owning module.
3. Onion metadata surface
Register the scene in package.json under zovaModule.onions.
Representative built-in pattern:
{
"service": {
"sceneIsolate": true,
"beanGeneral": true,
"optionsNone": false,
"optionsGlobalInterfaceFrom": "zova-module-a-bean",
"boilerplate": "service/boilerplate"
}
}2
3
4
5
6
7
8
9
This metadata is one of the main contracts for both bean creation and metadata generation.
4. CLI boilerplate and placement surface
The frontend :create:bean flow is scene-meta driven.
The command surface is:
npm run zova :create:bean sceneName beanName -- --module=...The generator reads scene metadata and decides where the file lives:
- isolated scene ->
src/<scene>/ - non-isolated scene ->
src/bean/
The public Zova CLI help currently exposes --module for this command, while boilerplate selection itself comes from scene metadata.
That means placement and scaffolding are part of scene definition, not later manual preferences.
Representative built-in boilerplate:
import { BeanBase } from 'zova';
import { Bean } from 'zova-module-a-bean';
@Bean()
export class Bean<%=argv.beanNameCapitalize%> extends BeanBase {
protected async __init__() {}
}2
3
4
5
6
7
5. Metadata generation surface
Frontend metadata generation is broader than simple file scaffolding.
The metadata flow scans frontend bean files and can generate:
- scene onion output
- scope resources
- bean typing in general or local record surfaces
- scene-specific custom metadata
- package and index side effects
That is why a new scene should be validated against generated .metadata/index.ts, not only against the decorator source.
How zovaModule.onions drives scene behavior
When authoring a scene, the most important design step is deciding the scene flags.
sceneIsolate
Use this when the scene should live in its own first-class folder such as src/service/.
If the flag is false, the generator normally places files under src/bean/ using the {scene}.{bean} naming pattern.
beanGeneral
Use this when the scene’s generated bean records should land in IBeanRecordGeneral rather than IBeanRecordLocal.
A practical distinction is:
beanGeneral: true-> generated bean records go toIBeanRecordGeneralbeanGeneral: false-> generated bean records still exist, but they go toIBeanRecordLocal
optionsNone
Use this to describe whether the scene decorator has no options payload.
If the scene decorator accepts structured options, this should align with the real decorator shape.
optionsGlobalInterfaceName and optionsGlobalInterfaceFrom
Use these when the scene needs a shared interface contract for decorator options.
This is especially useful when the scene’s options must be visible beyond one local file.
boilerplate
Use this to tell the CLI which template should be used when a bean of the scene is created.
Multiple boilerplate variants
A frontend scene can also expose more than one named template.
A practical rule is:
boilerplateprovides the default template--boilerplate=commandRowmaps toboilerplateCommandRow- more generally,
--boilerplate=namemaps toboilerplateName
This is useful when one scene needs multiple scaffold shapes for distinct frontend authoring paths.
Representative built-in examples include the command scene, which exposes commandBulk and commandRow variants, and the tableCell scene, which exposes a tableActionRow variant in module metadata.
For the built-in command scene’s runtime model, helper bases, metadata flow, and source-reading path, see Command Scene Authoring.
metadataCustom
Use this only when the scene needs additional generated output beyond the standard metadata passes.
A good rule is:
- start with the default metadata flow
- add custom metadata only when the scene has a real emitted contract that the default passes cannot express
Container-scope design is part of scene design
In Zova, the container scope is a core architectural decision.
Representative built-in scopes include:
sys: system-level singleton-style behaviorapp: app-scoped shared behaviorctx: component-instance or local-context behaviornew: fresh-instance behavior
Examples from built-in scenes:
@Sys()->sys@Bean()->ctx@Service()->ctx@Tool()->app@Data()->new@Api()->app@Model()->ctx
When adding a new scene, do not choose the scope cosmetically. The chosen scope affects how developers will resolve, share, and reason about that bean family.
Authoring flow for a new frontend scene
A practical Zova scene-authoring workflow is:
- choose the owning module for the scene
- decide the scene’s container scope
- add the scene decorator
- export it from the module
src/lib/index.ts - add the scene declaration-merging type and export it from
src/types/index.ts - add the scene under
zovaModule.onions - create the scene boilerplate for
:create:bean - add custom metadata generation if the scene needs extra emitted output
- run bean creation in a representative module
- inspect generated
.metadata/index.tsand file placement - only then write any additional scene-specific docs or business examples
What generated output should prove
A new scene is usually correct only if generated metadata proves the intended contract.
Depending on scene flags, inspect for output such as:
- scene registration in generated metadata
- scope resource output
- bean typing in the intended general or local record surface
- package/index export side effects
- correct placement under
src/beanorsrc/<scene>/
A useful point from the current source is that metadata generation does more than emit one file. It also updates package and index surfaces so the module stays coherent.
If the generated metadata or placement does not match the intended design, fix the scene contract first rather than patching generated output manually.
A useful split: adding a scene vs adding a bean
Keep these two tasks separate.
Add a bean inside an existing scene
Example:
npm run zova :create:bean model menu -- --module=training-studentThis uses an already-defined scene.
Add a new scene
This requires framework extension work:
- new decorator
- new scene type registration
- new container-scope decision
- new onion metadata entry
- new boilerplate
- optional metadata generation
That is why this topic belongs in an advanced guide.
Design rules for new scenes
Before adding a scene, ask these questions.
Which container should own the scene?
This is the most important frontend-specific question.
Choose the scope based on the real sharing and lifecycle contract:
sysfor system-wide singleton behaviorappfor app-shared behaviorctxfor local or component-context behaviornewfor fresh-instance behavior
Should the scene be isolated?
Choose an isolated scene when it deserves a first-class folder and operational identity.
Choose a non-isolated scene when it is better modeled as a bean-family variant under src/bean.
Should the scene use the general bean record surface?
Enable beanGeneral only when the scene should publish its generated bean records through IBeanRecordGeneral instead of the local record surface.
Does the scene need custom metadata?
Do not add custom metadata only because some built-in scenes do. Add it when the scene needs real emitted structures beyond the default metadata flow.
Relationship to existing guides
Read this guide together with:
Use the basic guides for normal bean creation. Use this page only when extending the scene system itself.
Verification checklist
When authoring or documenting a new frontend scene, verify in this order:
confirm the CLI command shape still exists:
bashnpm run zova :create:bean --help1confirm the scene decorator, scene typing, container scope, and
zovaModule.onionsentry agreecreate a test bean in a representative module
inspect whether the generated file goes to
src/bean/orsrc/<scene>/inspect
src/.metadata/index.tsin that moduleconfirm scope-resource, typing, and package/index output match the design
run the narrowest meaningful type or docs verification for the change
For repo-wide docs verification, also run:
npm run docs:build