cabloy 5.1.50 → 5.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/cabloy-backend-scaffold/SKILL.md +207 -0
- package/.claude/skills/cabloy-backend-scaffold/evals/evals.json +29 -0
- package/.claude/skills/cabloy-backend-scaffold/references/backend-thread-map.md +52 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +39 -0
- package/.claude/skills/cabloy-contract-loop/SKILL.md +201 -0
- package/.claude/skills/cabloy-contract-loop/evals/evals.json +29 -0
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +47 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -0
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +230 -0
- package/.claude/skills/cabloy-frontend-scaffold/evals/evals.json +35 -0
- package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +41 -0
- package/.claude/skills/cabloy-frontend-scaffold/references/frontend-thread-map.md +54 -0
- package/.claude/skills/cabloy-workflow/SKILL.md +288 -0
- package/.claude/skills/cabloy-workflow/evals/evals.json +35 -0
- package/.claude/skills/cabloy-workflow/references/cli-strategy.md +39 -0
- package/.claude/skills/cabloy-workflow/references/edition-detection.md +29 -0
- package/.github/workflows/docs-pages.yml +54 -0
- package/.gitignore +1 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +59 -0
- package/README.md +137 -0
- package/cabloy-docs/.vitepress/config.mjs +222 -0
- package/cabloy-docs/.vitepress/public/CNAME +1 -0
- package/cabloy-docs/.vitepress/theme/custom.css +64 -0
- package/cabloy-docs/.vitepress/theme/edition-badges.md +5 -0
- package/cabloy-docs/.vitepress/theme/index.js +5 -0
- package/cabloy-docs/ai/class-placement-rule.md +138 -0
- package/cabloy-docs/ai/cli-for-agents.md +56 -0
- package/cabloy-docs/ai/cli-to-skill-map.md +165 -0
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +167 -0
- package/cabloy-docs/ai/edition-detection.md +30 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +135 -0
- package/cabloy-docs/ai/global-bean-lookup.md +157 -0
- package/cabloy-docs/ai/introduction.md +62 -0
- package/cabloy-docs/ai/playbook-backend-module.md +111 -0
- package/cabloy-docs/ai/playbook-contract-regeneration.md +100 -0
- package/cabloy-docs/ai/playbook-frontend-page.md +99 -0
- package/cabloy-docs/ai/playbook-metadata-refresh.md +67 -0
- package/cabloy-docs/ai/repo-guidance.md +58 -0
- package/cabloy-docs/ai/rules-and-config.md +29 -0
- package/cabloy-docs/ai/skills.md +35 -0
- package/cabloy-docs/ai/verification.md +30 -0
- package/cabloy-docs/backend/aop-overview.md +128 -0
- package/cabloy-docs/backend/auth-guide.md +151 -0
- package/cabloy-docs/backend/backend-essentials.md +128 -0
- package/cabloy-docs/backend/broadcast-guide.md +138 -0
- package/cabloy-docs/backend/cache-guide.md +70 -0
- package/cabloy-docs/backend/captcha-guide.md +162 -0
- package/cabloy-docs/backend/cli.md +173 -0
- package/cabloy-docs/backend/config-guide.md +249 -0
- package/cabloy-docs/backend/controller-aop-guide.md +270 -0
- package/cabloy-docs/backend/controller-guide.md +347 -0
- package/cabloy-docs/backend/crud-workflow.md +118 -0
- package/cabloy-docs/backend/dto-guide.md +161 -0
- package/cabloy-docs/backend/dto-infer-generation.md +153 -0
- package/cabloy-docs/backend/dynamic-datasource-guide.md +70 -0
- package/cabloy-docs/backend/election-guide.md +141 -0
- package/cabloy-docs/backend/entity-guide.md +150 -0
- package/cabloy-docs/backend/error-guide.md +108 -0
- package/cabloy-docs/backend/event-guide.md +183 -0
- package/cabloy-docs/backend/external-aop-guide.md +149 -0
- package/cabloy-docs/backend/field-indexes.md +79 -0
- package/cabloy-docs/backend/foundation.md +281 -0
- package/cabloy-docs/backend/i18n-guide.md +211 -0
- package/cabloy-docs/backend/internal-aop-guide.md +181 -0
- package/cabloy-docs/backend/introduction.md +95 -0
- package/cabloy-docs/backend/jwt-guide.md +276 -0
- package/cabloy-docs/backend/logger-guide.md +223 -0
- package/cabloy-docs/backend/mail-guide.md +189 -0
- package/cabloy-docs/backend/menu-guide.md +80 -0
- package/cabloy-docs/backend/migration-and-changes.md +192 -0
- package/cabloy-docs/backend/model-guide.md +274 -0
- package/cabloy-docs/backend/multi-database-datasource.md +171 -0
- package/cabloy-docs/backend/multi-instance-and-instance-resolution.md +196 -0
- package/cabloy-docs/backend/openapi-guide.md +118 -0
- package/cabloy-docs/backend/orm-aggregate-group-guide.md +210 -0
- package/cabloy-docs/backend/orm-configuration-guide.md +165 -0
- package/cabloy-docs/backend/orm-guide.md +109 -0
- package/cabloy-docs/backend/orm-mutation-guide.md +195 -0
- package/cabloy-docs/backend/orm-select-guide.md +243 -0
- package/cabloy-docs/backend/queue-guide.md +271 -0
- package/cabloy-docs/backend/quickstart.md +141 -0
- package/cabloy-docs/backend/redis-guide.md +70 -0
- package/cabloy-docs/backend/redlock-guide.md +60 -0
- package/cabloy-docs/backend/relations-guide.md +250 -0
- package/cabloy-docs/backend/runtime-and-flavors.md +304 -0
- package/cabloy-docs/backend/schedule-guide.md +81 -0
- package/cabloy-docs/backend/scripts.md +116 -0
- package/cabloy-docs/backend/serialization-guide.md +192 -0
- package/cabloy-docs/backend/service-guide.md +166 -0
- package/cabloy-docs/backend/sharding-guide.md +49 -0
- package/cabloy-docs/backend/startup-guide.md +326 -0
- package/cabloy-docs/backend/transaction-guide.md +82 -0
- package/cabloy-docs/backend/unit-testing.md +209 -0
- package/cabloy-docs/backend/upload-guide.md +160 -0
- package/cabloy-docs/backend/user-access-guide.md +157 -0
- package/cabloy-docs/backend/validation-guide.md +80 -0
- package/cabloy-docs/backend/worker-guide.md +59 -0
- package/cabloy-docs/editions/cabloy-basic.md +25 -0
- package/cabloy-docs/editions/cabloy-start.md +24 -0
- package/cabloy-docs/editions/detection.md +31 -0
- package/cabloy-docs/editions/overview.md +44 -0
- package/cabloy-docs/frontend/api-guide.md +93 -0
- package/cabloy-docs/frontend/api-schema-guide.md +43 -0
- package/cabloy-docs/frontend/app-startup-guide.md +185 -0
- package/cabloy-docs/frontend/cli.md +78 -0
- package/cabloy-docs/frontend/component-guide.md +105 -0
- package/cabloy-docs/frontend/component-props-guide.md +97 -0
- package/cabloy-docs/frontend/component-v-model-guide.md +110 -0
- package/cabloy-docs/frontend/css-in-js-guide.md +151 -0
- package/cabloy-docs/frontend/design-principles.md +55 -0
- package/cabloy-docs/frontend/environment-config-guide.md +250 -0
- package/cabloy-docs/frontend/foundation.md +57 -0
- package/cabloy-docs/frontend/generic-component-guide.md +35 -0
- package/cabloy-docs/frontend/icon-engine-guide.md +88 -0
- package/cabloy-docs/frontend/introduction.md +32 -0
- package/cabloy-docs/frontend/ioc-and-beans.md +211 -0
- package/cabloy-docs/frontend/mock-guide.md +109 -0
- package/cabloy-docs/frontend/model-architecture.md +87 -0
- package/cabloy-docs/frontend/model-state-guide.md +70 -0
- package/cabloy-docs/frontend/module-scope.md +168 -0
- package/cabloy-docs/frontend/modules-and-suites.md +179 -0
- package/cabloy-docs/frontend/navigation-guards-guide.md +68 -0
- package/cabloy-docs/frontend/openapi-sdk-guide.md +102 -0
- package/cabloy-docs/frontend/page-guide.md +223 -0
- package/cabloy-docs/frontend/page-params-guide.md +87 -0
- package/cabloy-docs/frontend/page-query-guide.md +96 -0
- package/cabloy-docs/frontend/page-route-guide.md +147 -0
- package/cabloy-docs/frontend/quickstart.md +201 -0
- package/cabloy-docs/frontend/route-alias-guide.md +61 -0
- package/cabloy-docs/frontend/scripts.md +86 -0
- package/cabloy-docs/frontend/sdk-guide.md +45 -0
- package/cabloy-docs/frontend/server-data.md +74 -0
- package/cabloy-docs/frontend/ssr-client-only.md +40 -0
- package/cabloy-docs/frontend/ssr-env.md +51 -0
- package/cabloy-docs/frontend/ssr-init-data.md +46 -0
- package/cabloy-docs/frontend/ssr-overview.md +48 -0
- package/cabloy-docs/frontend/ssr-seo-meta.md +52 -0
- package/cabloy-docs/frontend/system-startup-guide.md +186 -0
- package/cabloy-docs/frontend/theme-guide.md +154 -0
- package/cabloy-docs/frontend/zod-guide.md +161 -0
- package/cabloy-docs/fullstack/edition-collaboration-differences.md +61 -0
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +64 -0
- package/cabloy-docs/fullstack/introduction.md +69 -0
- package/cabloy-docs/fullstack/openapi-to-sdk.md +116 -0
- package/cabloy-docs/fullstack/quickstart.md +86 -0
- package/cabloy-docs/fullstack/vona-zova-integration.md +86 -0
- package/cabloy-docs/index.md +73 -0
- package/cabloy-docs/package.json +16 -0
- package/cabloy-docs/pnpm-lock.yaml +1607 -0
- package/cabloy-docs/reference/backend-directory-structure.md +88 -0
- package/cabloy-docs/reference/cli-reference.md +49 -0
- package/cabloy-docs/reference/glossary.md +38 -0
- package/cabloy-docs/reference/package-map.md +105 -0
- package/cabloy-docs/reference/repo-scripts.md +36 -0
- package/package.json +4 -1
- package/scripts/init.ts +12 -0
- package/scripts/upgrade.ts +31 -3
- package/vona/README.md +3 -3
- package/vona/README.zh-CN.md +4 -4
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-datasharding/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-datasharding/src/bean/summerCache.datasourceWrite.ts +2 -2
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- package/vona/src/suite-vendor/a-captcha/modules/a-captcha/package.json +1 -1
- package/vona/src/suite-vendor/a-captcha/modules/a-captcha/src/bean/cacheRedis.captcha.ts +2 -2
- package/vona/src/suite-vendor/a-captcha/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-bean/cli/bean/metadata/generate.ts +5 -6
- package/vona/src/suite-vendor/a-vona/modules/a-bean/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-cache/cli/cacheMem/boilerplate/{{sceneName}}.{{beanName}}.ts_ +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-cache/cli/cacheRedis/boilerplate/{{sceneName}}.{{beanName}}.ts_ +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-cache/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-cache/src/.metadata/index.ts +13 -2
- package/vona/src/suite-vendor/a-vona/modules/a-cache/src/bean/bean.cache.ts +6 -7
- package/vona/src/suite-vendor/a-vona/modules/a-cache/src/{bean/bean.cacheMemBase.ts → service/cacheMemBase_.ts} +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-cache/src/{bean/bean.cacheRedisBase.ts → service/cacheRedisBase_.ts} +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-mailconfirm/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-mailconfirm/src/bean/cacheRedis.emailConfirm.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-mailconfirm/src/bean/cacheRedis.passwordReset.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/src/bean/summerCache.json.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-orm/cli/databaseDialect/boilerplate/{{sceneName}}.{{beanName}}.ts_ +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/.metadata/index.ts +4 -3
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/bean/bean.database.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/bean/bean.model.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/bean/schedule.softDeletionPrune.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/common/utils.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/index.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_cache.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_meta.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.modelBase.ts +0 -5
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoAggregate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoCreate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoGet.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoGroup.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoMutate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoSelectAndCount.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoUpdate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/index.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/modelCacheBase.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/relations.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/relationsDynamic.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/relationsMutate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/relationsStatic.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/service/cacheEntity_.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/service/cacheQuery_.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/service/database.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean/bean.databaseDialectBase.ts → service/databaseDialectBase_.ts} +38 -41
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/service/db_.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/service/relations_.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/database.ts +0 -5
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/dto/dtoGet.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/dto/dtoMutate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/dto/dtoSelectAndCount.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/model.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/modelAggr.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/modelCount.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/modelGeneral.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/modelGroup.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/modelIncrement.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relations.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsColumns.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsDef.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsDefDynamic.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsDefMutate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsMutate.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/relationsTables.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/bean/databaseDialect.betterSqlite3.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/bean/databaseDialect.mysql.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/bean/databaseDialect.pg.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +109 -40
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permission.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-startup/src/bean/cacheRedis.startupDebounce.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-summer/cli/boilerplate/{{sceneName}}.{{beanName}}.ts_ +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-summer/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-summer/src/.metadata/index.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-summer/src/bean/bean.summer.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-summer/src/service/localMem_.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-summer/src/service/localRedis_.ts +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-summer/src/{bean/bean.summerCacheBase.ts → service/summerCacheBase_.ts} +3 -3
- package/vona/src/suite-vendor/a-vona/modules/a-swagger/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-swagger/src/bean/summerCache.rapidoc.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-swagger/src/bean/summerCache.swagger.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/cacheRedis.authToken.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-worker/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-worker/src/bean/cacheRedis.workerAlive.ts +2 -2
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/README.md +4 -4
- package/zova/README.zh-CN.md +4 -4
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_crud.ts +0 -0
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_crud_inner.ts +0 -0
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_crud_table.ts +0 -0
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_knex.ts +0 -0
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_utils.ts +0 -0
- /package/vona/src/suite-vendor/a-vona/modules/a-orm/src/{bean → lib}/bean.model/bean.model_view.ts +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Entity Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how entities work in Vona within the Cabloy monorepo.
|
|
4
|
+
|
|
5
|
+
## Why entities matter in the contract loop
|
|
6
|
+
|
|
7
|
+
Entities are not only persistence records. In Vona, they also participate in validation, OpenAPI metadata, serializer-facing response shape, and downstream DTO design.
|
|
8
|
+
|
|
9
|
+
That makes entity design one of the main places where database structure and API contract structure meet.
|
|
10
|
+
|
|
11
|
+
## Create an entity
|
|
12
|
+
|
|
13
|
+
Example: create an entity named `student` in module `demo-student`.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run vona :create:bean entity student -- --module=demo-student
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Entity definition
|
|
20
|
+
|
|
21
|
+
Representative pattern:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
@Entity<IEntityOptionsStudent>('demoStudent')
|
|
25
|
+
export class EntityStudent extends EntityBase {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The entity defines the table-oriented data shape that the model layer works with.
|
|
29
|
+
|
|
30
|
+
## Entities in the backend contract loop
|
|
31
|
+
|
|
32
|
+
Entities sit at an important boundary:
|
|
33
|
+
|
|
34
|
+
- models bind to entities
|
|
35
|
+
- DTOs can reuse entity field structure
|
|
36
|
+
- validation can infer schema from entity field declarations
|
|
37
|
+
- OpenAPI metadata can be emitted from the same field surface
|
|
38
|
+
|
|
39
|
+
Read this guide together with:
|
|
40
|
+
|
|
41
|
+
- [Model Guide](/backend/model-guide)
|
|
42
|
+
- [DTO Guide](/backend/dto-guide)
|
|
43
|
+
- [Validation Guide](/backend/validation-guide)
|
|
44
|
+
- [OpenAPI Guide](/backend/openapi-guide)
|
|
45
|
+
|
|
46
|
+
## Table-name convention
|
|
47
|
+
|
|
48
|
+
Vona’s modular system needs a safe table-naming convention to reduce conflicts.
|
|
49
|
+
|
|
50
|
+
General pattern:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
tableName = moduleName + entityName
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If the entity name duplicates the module name, Vona removes the duplicate fragment.
|
|
57
|
+
|
|
58
|
+
This convention matters because AI systems should not invent arbitrary table names when the framework already has a stable naming model.
|
|
59
|
+
|
|
60
|
+
## `@Api.field` as the shared contract surface
|
|
61
|
+
|
|
62
|
+
A key Vona idea is that entity fields can simultaneously express:
|
|
63
|
+
|
|
64
|
+
- field type
|
|
65
|
+
- validation rules
|
|
66
|
+
- OpenAPI metadata
|
|
67
|
+
- serializer-oriented response metadata
|
|
68
|
+
|
|
69
|
+
That is why entity fields are centered around `@Api.field`.
|
|
70
|
+
|
|
71
|
+
Representative pattern:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
class EntityStudent {
|
|
75
|
+
@Api.field()
|
|
76
|
+
name: string;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This is one of the strongest backend-contract-loop ideas: the same field definition can drive runtime validation and machine-readable API description without duplicating the contract in several places.
|
|
81
|
+
|
|
82
|
+
## Automatic schema inference
|
|
83
|
+
|
|
84
|
+
If the field type is a basic type, DTO, or entity, Vona can automatically infer the corresponding schema and OpenAPI output.
|
|
85
|
+
|
|
86
|
+
Representative automatically inferred types include:
|
|
87
|
+
|
|
88
|
+
- `string`
|
|
89
|
+
- `number`
|
|
90
|
+
- `boolean`
|
|
91
|
+
- DTO classes
|
|
92
|
+
- Entity classes
|
|
93
|
+
|
|
94
|
+
This matters because entity design is not only about persistence columns. It also affects how much explicit schema authoring you need later.
|
|
95
|
+
|
|
96
|
+
## Explicit schema extension
|
|
97
|
+
|
|
98
|
+
When inference is not enough, you can extend the field definition with richer schema and metadata.
|
|
99
|
+
|
|
100
|
+
Representative examples include:
|
|
101
|
+
|
|
102
|
+
- explicit schema rules such as `z.number().min(18)`
|
|
103
|
+
- helpers such as `v.default`, `v.optional`, `v.array`
|
|
104
|
+
- OpenAPI metadata such as `v.title`, `v.description`, `v.example`, `v.openapi`
|
|
105
|
+
|
|
106
|
+
A practical rule is:
|
|
107
|
+
|
|
108
|
+
- use inference for straightforward fields
|
|
109
|
+
- add explicit schema or metadata only where the contract really needs more detail
|
|
110
|
+
|
|
111
|
+
## Entity options
|
|
112
|
+
|
|
113
|
+
Important entity-option areas include:
|
|
114
|
+
|
|
115
|
+
- `table`
|
|
116
|
+
- `independent`
|
|
117
|
+
- `openapi`
|
|
118
|
+
- `fields`
|
|
119
|
+
|
|
120
|
+
These options matter because the entity can influence not only table mapping but also how the entity appears in the machine-readable contract layer.
|
|
121
|
+
|
|
122
|
+
## App-config overrides
|
|
123
|
+
|
|
124
|
+
Entity options can also be configured through app config.
|
|
125
|
+
|
|
126
|
+
This matters because entity-facing contract metadata can be refined at the project level without rewriting the entity class directly.
|
|
127
|
+
|
|
128
|
+
## Base class and identity type
|
|
129
|
+
|
|
130
|
+
By default, entities inherit from `EntityBase`, which provides common fields such as:
|
|
131
|
+
|
|
132
|
+
- `id`
|
|
133
|
+
- `createdAt`
|
|
134
|
+
- `updatedAt`
|
|
135
|
+
- `deleted`
|
|
136
|
+
- `iid`
|
|
137
|
+
|
|
138
|
+
The `id` field uses `TableIdentity`, which supports both string and number representations depending on the configured identity strategy.
|
|
139
|
+
|
|
140
|
+
That matters because contract types should not assume a narrower identity shape than the backend actually supports.
|
|
141
|
+
|
|
142
|
+
## Implementation checks for entity changes
|
|
143
|
+
|
|
144
|
+
When creating or updates entities:
|
|
145
|
+
|
|
146
|
+
1. preserve Vona table-naming conventions unless there is a deliberate reason to override them
|
|
147
|
+
2. use `@Api.field` rather than scattering schema and metadata concerns inconsistently
|
|
148
|
+
3. keep validation, OpenAPI, serializer, and entity structure aligned
|
|
149
|
+
4. remember that entities feed DTO, model, and OpenAPI workflows downstream
|
|
150
|
+
5. keep identity and base-field assumptions consistent with the actual backend contract loop
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Error Guide
|
|
2
|
+
|
|
3
|
+
## Why error matters as a backend scope resource
|
|
4
|
+
|
|
5
|
+
In Vona, module errors are not only thrown values. They are part of a module-scoped resource model that connects error codes, localized messages, and cross-module reuse.
|
|
6
|
+
|
|
7
|
+
That matters because backend contracts often need errors that are:
|
|
8
|
+
|
|
9
|
+
- typed by convention
|
|
10
|
+
- localized through module locale resources
|
|
11
|
+
- reusable through module scope
|
|
12
|
+
- override-friendly at the project level when wording changes are needed
|
|
13
|
+
|
|
14
|
+
## Initialize the error skeleton
|
|
15
|
+
|
|
16
|
+
Example: initialize error resources for module `demo-student`.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run vona :init:error demo-student
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This gives the module the standard files for defining error codes and their language resources.
|
|
23
|
+
|
|
24
|
+
## Define module errors
|
|
25
|
+
|
|
26
|
+
Defining an error takes two main steps.
|
|
27
|
+
|
|
28
|
+
### 1. Define the error codes
|
|
29
|
+
|
|
30
|
+
Representative pattern:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
export const errors = {
|
|
34
|
+
ErrorTest: 1001,
|
|
35
|
+
} as const;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A useful convention is that business error codes should stay above `1000`.
|
|
39
|
+
|
|
40
|
+
### 2. Define the localized error messages
|
|
41
|
+
|
|
42
|
+
Representative locale pattern:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
export default {
|
|
46
|
+
ErrorTest: 'This is a error test',
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This is the key architectural point: the error definition and the localized wording are related, but they live in separate resources.
|
|
51
|
+
|
|
52
|
+
## Use error within the current module
|
|
53
|
+
|
|
54
|
+
The current module’s errors can be reached through scope.
|
|
55
|
+
|
|
56
|
+
Representative pattern:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
this.scope.error.ErrorTest.throw();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Use error across modules
|
|
63
|
+
|
|
64
|
+
Cross-module error access uses the cross-module scope surface.
|
|
65
|
+
|
|
66
|
+
Representative pattern:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
this.$scope.demoStudent.error.ErrorTest.throw();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A practical distinction is:
|
|
73
|
+
|
|
74
|
+
- `this.scope.error` for the current module
|
|
75
|
+
- `this.$scope.<module>.error` for another module
|
|
76
|
+
|
|
77
|
+
## Relationship to locale resources
|
|
78
|
+
|
|
79
|
+
Module errors are closely connected to module locale resources.
|
|
80
|
+
|
|
81
|
+
That means this guide should be read together with [I18n Guide](/backend/i18n-guide).
|
|
82
|
+
|
|
83
|
+
A useful ownership rule is:
|
|
84
|
+
|
|
85
|
+
- the error code defines the backend exception identity
|
|
86
|
+
- locale resources define the user-facing or developer-facing wording
|
|
87
|
+
- scope makes both available through the module resource model
|
|
88
|
+
|
|
89
|
+
## Relationship to backend essentials
|
|
90
|
+
|
|
91
|
+
Errors are one of the clearest examples of why backend scope matters.
|
|
92
|
+
|
|
93
|
+
Read this guide together with:
|
|
94
|
+
|
|
95
|
+
- [Backend Essentials](/backend/backend-essentials)
|
|
96
|
+
- [Backend Foundation](/backend/foundation)
|
|
97
|
+
- [I18n Guide](/backend/i18n-guide)
|
|
98
|
+
|
|
99
|
+
## Implementation checks for backend error-handling changes
|
|
100
|
+
|
|
101
|
+
When editing backend error behavior, ask:
|
|
102
|
+
|
|
103
|
+
1. should this error be defined as a module-scoped error instead of an inline throw?
|
|
104
|
+
2. does the error need localized wording in locale resources?
|
|
105
|
+
3. should the error be consumed from the current module or across modules?
|
|
106
|
+
4. is the existing module error skeleton the right place to extend instead of inventing a separate error pattern?
|
|
107
|
+
|
|
108
|
+
That helps AI keep backend error handling aligned with Vona’s module-resource model and localization system.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Event Guide
|
|
2
|
+
|
|
3
|
+
## Why events matter in Vona
|
|
4
|
+
|
|
5
|
+
Vona provides a framework-native event mechanism so backend code can publish extensible business signals without hardwiring every downstream action into one method body.
|
|
6
|
+
|
|
7
|
+
That matters because registration, activation, auditing, notifications, and other backend workflows often need layered reactions that should remain composable.
|
|
8
|
+
|
|
9
|
+
## Core event model
|
|
10
|
+
|
|
11
|
+
Vona’s event system is built around two concepts:
|
|
12
|
+
|
|
13
|
+
- **event**
|
|
14
|
+
- **event listener**
|
|
15
|
+
|
|
16
|
+
An event can have multiple listeners, and listeners execute with an onion-style chaining model.
|
|
17
|
+
|
|
18
|
+
That means listeners can:
|
|
19
|
+
|
|
20
|
+
- observe the event
|
|
21
|
+
- modify the event data before passing it onward
|
|
22
|
+
- wrap the next listener or default method
|
|
23
|
+
- contribute to the final result
|
|
24
|
+
|
|
25
|
+
## Event definition
|
|
26
|
+
|
|
27
|
+
An event is defined as a typed bean.
|
|
28
|
+
|
|
29
|
+
Representative generation workflow:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run vona :create:bean event echo -- --module=demo-student
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Representative pattern:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
export type TypeEventEchoData = string;
|
|
39
|
+
export type TypeEventEchoResult = string | undefined;
|
|
40
|
+
|
|
41
|
+
@Event()
|
|
42
|
+
export class EventEcho extends BeanEventBase<TypeEventEchoData, TypeEventEchoResult> {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This makes event payload and result types part of the framework model instead of untyped side-channel data.
|
|
46
|
+
|
|
47
|
+
## Emitting events
|
|
48
|
+
|
|
49
|
+
### Asynchronous emit
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const result = await this.scope.event.echo.emit('Hello World');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Synchronous emit
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const result = this.scope.event.echo.emitSync('Hello World');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Default method support
|
|
62
|
+
|
|
63
|
+
Both `emit` and `emitSync` can accept a default method.
|
|
64
|
+
|
|
65
|
+
Representative pattern:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const result = await this.scope.event.echo.emit('Hello World', async data => {
|
|
69
|
+
return `default: ${data}`;
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The default method receives the latest event data after listener processing, which is important because listeners can transform the payload before passing it onward.
|
|
74
|
+
|
|
75
|
+
## Event listener definition
|
|
76
|
+
|
|
77
|
+
Event listeners attach through `@EventListener({ match: ... })`.
|
|
78
|
+
|
|
79
|
+
Representative generation workflow:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run vona :create:bean eventListener echo -- --module=demo-student
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Representative pattern:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
@EventListener({ match: 'demo-student:echo' })
|
|
89
|
+
export class EventListenerEcho implements IEventExecute<TypeEventData, TypeEventResult> {
|
|
90
|
+
execute(data: TypeEventData, next: NextEventSync<TypeEventData, TypeEventResult>) {
|
|
91
|
+
const dataNew = `${data}!`;
|
|
92
|
+
return next(dataNew);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This pattern shows the key ideas:
|
|
98
|
+
|
|
99
|
+
- listeners match one or more named events
|
|
100
|
+
- listeners can transform event data
|
|
101
|
+
- listeners pass control onward through `next(...)`
|
|
102
|
+
|
|
103
|
+
A practical typing rule is to import the event’s data/result types into the listener instead of redefining them independently, so the event contract stays coupled at the type level while remaining decoupled at the execution level.
|
|
104
|
+
|
|
105
|
+
## Event ordering
|
|
106
|
+
|
|
107
|
+
Multiple listeners can attach to the same event.
|
|
108
|
+
|
|
109
|
+
Vona supports execution ordering through:
|
|
110
|
+
|
|
111
|
+
- `dependencies`
|
|
112
|
+
- `dependents`
|
|
113
|
+
|
|
114
|
+
That allows event listener chains to stay explicit instead of relying on accidental load order.
|
|
115
|
+
|
|
116
|
+
A useful rule of thumb is:
|
|
117
|
+
|
|
118
|
+
- use `dependencies` when another listener must run before the current one
|
|
119
|
+
- use `dependents` when the current listener must run before another named listener
|
|
120
|
+
|
|
121
|
+
## Enable/disable and runtime scope
|
|
122
|
+
|
|
123
|
+
Event listeners can be controlled through:
|
|
124
|
+
|
|
125
|
+
- app-config enable/disable
|
|
126
|
+
- `mode`
|
|
127
|
+
- `flavor`
|
|
128
|
+
|
|
129
|
+
This is important because some event-driven behavior should only apply in certain environments.
|
|
130
|
+
|
|
131
|
+
## Inspection
|
|
132
|
+
|
|
133
|
+
Vona can inspect the effective event-listener list for a named event.
|
|
134
|
+
|
|
135
|
+
Representative pattern:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
this.bean.onion.eventListener.inspectEventListener('demo-student:echo');
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This is useful for debugging event composition and verifying which listeners are active.
|
|
142
|
+
|
|
143
|
+
That inspect step is especially valuable before changing ordering metadata, because it lets you confirm the effective chain first instead of guessing from module load order.
|
|
144
|
+
|
|
145
|
+
## Relationship to user-access workflows
|
|
146
|
+
|
|
147
|
+
The event model is especially important in user-access flows.
|
|
148
|
+
|
|
149
|
+
Representative examples include:
|
|
150
|
+
|
|
151
|
+
- registration events
|
|
152
|
+
- activation events
|
|
153
|
+
- post-registration follow-up such as email confirmation
|
|
154
|
+
- role-assignment follow-up logic
|
|
155
|
+
|
|
156
|
+
Mail delivery is a common downstream effect in these flows; see [Mail Guide](/backend/mail-guide).
|
|
157
|
+
|
|
158
|
+
Read this together with [User Access Guide](/backend/user-access-guide) when the event flow is tied to identity lifecycle behavior.
|
|
159
|
+
|
|
160
|
+
## When to use events instead of direct calls
|
|
161
|
+
|
|
162
|
+
Use events when:
|
|
163
|
+
|
|
164
|
+
- one business action may need multiple follow-up behaviors
|
|
165
|
+
- extension logic should remain decoupled from the initiating method
|
|
166
|
+
- you want project-level customization without rewriting the original flow
|
|
167
|
+
|
|
168
|
+
Use direct calls when:
|
|
169
|
+
|
|
170
|
+
- the behavior is tightly bound to the core logic and should not be extensible as a chain
|
|
171
|
+
|
|
172
|
+
A practical example from the user-access layer is registration and activation: the core user flow can stay small, while follow-up concerns such as mail confirmation or role assignment move into listeners.
|
|
173
|
+
|
|
174
|
+
## Implementation checks for event-driven backend changes
|
|
175
|
+
|
|
176
|
+
When editing event-driven backend behavior, ask:
|
|
177
|
+
|
|
178
|
+
1. should this be an event instead of a direct call chain?
|
|
179
|
+
2. is the payload/result shape already captured by an existing typed event?
|
|
180
|
+
3. does the workflow need synchronous or asynchronous event emission?
|
|
181
|
+
4. should listener ordering, enable/disable, or runtime environment rules be explicit?
|
|
182
|
+
|
|
183
|
+
That helps AI keep extension logic aligned with Vona’s event model instead of embedding it into unrelated service methods.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# External AOP Guide
|
|
2
|
+
|
|
3
|
+
## Why external AOP matters
|
|
4
|
+
|
|
5
|
+
External AOP lets Vona attach behavior to another class from the outside without editing that class directly.
|
|
6
|
+
|
|
7
|
+
This matters when the extension logic should remain decoupled from the target class source while still participating in the framework’s typed bean model.
|
|
8
|
+
|
|
9
|
+
## Core model
|
|
10
|
+
|
|
11
|
+
External AOP uses `@Aop({ match: ... })` to associate an aspect class with one or more target classes by bean name.
|
|
12
|
+
|
|
13
|
+
Representative CLI generation pattern:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run vona :create:bean aop log -- --module=demo-student
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Representative shape:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
@Aop({ match: 'demo-student.service.test' })
|
|
23
|
+
export class AopLog extends BeanAopBase {}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The `match` option determines which classes the external aspect applies to.
|
|
27
|
+
|
|
28
|
+
## What external AOP can intercept
|
|
29
|
+
|
|
30
|
+
External AOP can extend:
|
|
31
|
+
|
|
32
|
+
- synchronous methods
|
|
33
|
+
- asynchronous methods
|
|
34
|
+
- getters
|
|
35
|
+
- setters
|
|
36
|
+
- `__init__`
|
|
37
|
+
- `__dispose__`
|
|
38
|
+
- generic method dispatch through `__method__`
|
|
39
|
+
- magic-method style behavior such as `__get__` and `__set__`
|
|
40
|
+
|
|
41
|
+
## Representative method interception
|
|
42
|
+
|
|
43
|
+
### Synchronous method
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
actionSync: AopAction<ServiceTest, 'actionSync'> = (_args, next) => {
|
|
47
|
+
const timeBegin = Date.now();
|
|
48
|
+
const res = next();
|
|
49
|
+
const timeEnd = Date.now();
|
|
50
|
+
console.log('actionSync: ', timeEnd - timeBegin);
|
|
51
|
+
return res;
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Asynchronous method
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
actionAsync: AopAction<ServiceTest, 'actionAsync'> = async (_args, next) => {
|
|
59
|
+
const timeBegin = Date.now();
|
|
60
|
+
const res = await next();
|
|
61
|
+
const timeEnd = Date.now();
|
|
62
|
+
console.log('actionAsync: ', timeEnd - timeBegin);
|
|
63
|
+
return res;
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Getter and setter interception
|
|
68
|
+
|
|
69
|
+
External AOP can also wrap property access:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
protected __get_name__: AopActionGetter<ServiceTest, 'name'> = function (next) {
|
|
73
|
+
const value = next();
|
|
74
|
+
return value;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
protected __set_name__: AopActionSetter<ServiceTest, 'name'> = function (value, next) {
|
|
78
|
+
return next(value);
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This is especially useful when you want to observe or constrain property access without moving that concern into the target class source.
|
|
83
|
+
|
|
84
|
+
## Lifecycle interception
|
|
85
|
+
|
|
86
|
+
You can extend lifecycle hooks such as:
|
|
87
|
+
|
|
88
|
+
- `__init__`
|
|
89
|
+
- `__dispose__`
|
|
90
|
+
|
|
91
|
+
That allows setup and teardown behavior to be wrapped externally when needed.
|
|
92
|
+
|
|
93
|
+
## Generic magic-method interception
|
|
94
|
+
|
|
95
|
+
External AOP also supports broader interception points such as:
|
|
96
|
+
|
|
97
|
+
- `__get__`
|
|
98
|
+
- `__set__`
|
|
99
|
+
- `__method__`
|
|
100
|
+
|
|
101
|
+
This makes it possible to add dynamic behavior such as custom virtual properties or broad method-level logging without editing the target class source.
|
|
102
|
+
|
|
103
|
+
## Ordering and runtime controls
|
|
104
|
+
|
|
105
|
+
External AOP supports the same kinds of runtime controls seen elsewhere in Vona:
|
|
106
|
+
|
|
107
|
+
- `dependencies`
|
|
108
|
+
- `dependents`
|
|
109
|
+
- enable/disable
|
|
110
|
+
- `mode`
|
|
111
|
+
- `flavor`
|
|
112
|
+
- inspection of the effective AOP list
|
|
113
|
+
|
|
114
|
+
Representative inspect pattern:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
this.bean.onion.aop.inspect();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
That becomes especially helpful when more than one external aspect matches the same target bean and you need to confirm the effective chain before changing ordering metadata.
|
|
121
|
+
|
|
122
|
+
## When to use external AOP instead of internal AOP
|
|
123
|
+
|
|
124
|
+
Use this rule of thumb:
|
|
125
|
+
|
|
126
|
+
- use **internal AOP** when the behavior belongs naturally inside the target class or its decorator surface
|
|
127
|
+
- use **external AOP** when the behavior should be attached from outside by bean match and remain decoupled from the target class definition
|
|
128
|
+
|
|
129
|
+
A good concrete signal for external AOP is when one extension should apply to an existing service or bean without forcing that bean to import new decorators or framework logic just to host the concern.
|
|
130
|
+
|
|
131
|
+
## Relationship to internal AOP
|
|
132
|
+
|
|
133
|
+
External AOP and internal AOP solve similar extension problems, but with different ownership models:
|
|
134
|
+
|
|
135
|
+
- **internal AOP** decorates the class from within its own source
|
|
136
|
+
- **external AOP** attaches behavior from the outside by match
|
|
137
|
+
|
|
138
|
+
Read this page together with [Internal AOP Guide](/backend/internal-aop-guide).
|
|
139
|
+
|
|
140
|
+
## Questions for external AOP changes
|
|
141
|
+
|
|
142
|
+
When extending a backend class, ask:
|
|
143
|
+
|
|
144
|
+
1. should this behavior live in the class source or outside it?
|
|
145
|
+
2. is the target identified more naturally by bean name matching?
|
|
146
|
+
3. does the extension need to intercept methods, accessors, lifecycle hooks, or magic-method behavior?
|
|
147
|
+
4. does ordering or runtime environment control matter for this aspect?
|
|
148
|
+
|
|
149
|
+
That helps AI choose a Vona-native extension model instead of patching behavior manually into unrelated code.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Field Indexes
|
|
2
|
+
|
|
3
|
+
This guide explains how field indexes work in Vona within the Cabloy monorepo.
|
|
4
|
+
|
|
5
|
+
## Why field indexes are a first-class concept
|
|
6
|
+
|
|
7
|
+
Vona provides a framework-level mechanism for declaring field indexes and having the system create them automatically.
|
|
8
|
+
|
|
9
|
+
That is important because indexing is not treated as an afterthought. It is part of module metadata.
|
|
10
|
+
|
|
11
|
+
## `meta.index`
|
|
12
|
+
|
|
13
|
+
Vona uses a bean named `meta.index` to configure a module’s field indexes.
|
|
14
|
+
|
|
15
|
+
Create it with:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run vona :create:bean meta index -- --module=demo-student
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Representative shell:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
@Meta()
|
|
25
|
+
export class MetaIndex extends BeanBase {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configure indexes: direct style
|
|
29
|
+
|
|
30
|
+
Representative pattern:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
@Meta({
|
|
34
|
+
indexes: {
|
|
35
|
+
demoStudent: 'name',
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
class MetaIndex {}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This expresses:
|
|
42
|
+
|
|
43
|
+
- table name
|
|
44
|
+
- field name or field-name list
|
|
45
|
+
|
|
46
|
+
## Configure indexes: typed style
|
|
47
|
+
|
|
48
|
+
A typed style is also supported:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { $tableColumns } from 'vona-module-a-ormutils';
|
|
52
|
+
|
|
53
|
+
@Meta({
|
|
54
|
+
indexes: {
|
|
55
|
+
...$tableColumns('demoStudent', 'name'),
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
class MetaIndex {}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This is especially valuable for maintainability because it reduces stringly-typed drift.
|
|
62
|
+
|
|
63
|
+
## App-config override support
|
|
64
|
+
|
|
65
|
+
Field indexes can also be configured through app config.
|
|
66
|
+
|
|
67
|
+
That means index behavior participates in the broader configuration system rather than being locked into one metadata file only.
|
|
68
|
+
|
|
69
|
+
## Implementation checks for persistence changes
|
|
70
|
+
|
|
71
|
+
When changing persistence design, do not stop at entity fields and model methods.
|
|
72
|
+
|
|
73
|
+
Also ask:
|
|
74
|
+
|
|
75
|
+
1. does this access pattern need an index?
|
|
76
|
+
2. should the index belong in `meta.index`?
|
|
77
|
+
3. is the typed style a better fit than raw string declarations?
|
|
78
|
+
|
|
79
|
+
That leads to backend changes that are more production-aware and more aligned with Vona’s module metadata model.
|