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,274 @@
|
|
|
1
|
+
# Model Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how models work in Vona within the Cabloy monorepo.
|
|
4
|
+
|
|
5
|
+
## Why models matter in the backend contract loop
|
|
6
|
+
|
|
7
|
+
Models are the persistence-facing layer of the backend contract loop.
|
|
8
|
+
|
|
9
|
+
A useful split is:
|
|
10
|
+
|
|
11
|
+
- controllers define HTTP-facing contracts
|
|
12
|
+
- services orchestrate business flow
|
|
13
|
+
- models own ORM-facing persistence behavior
|
|
14
|
+
- entities and DTOs shape the data contract around that behavior
|
|
15
|
+
|
|
16
|
+
That means model design affects not only SQL behavior, but also CRUD defaults, DTO assumptions, OpenAPI-facing contracts, and test setup.
|
|
17
|
+
|
|
18
|
+
## Create a model
|
|
19
|
+
|
|
20
|
+
Example: create a model named `student` in module `demo-student`.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run vona :create:bean model student -- --module=demo-student
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Model definition
|
|
27
|
+
|
|
28
|
+
Representative pattern:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { BeanModelBase, Model } from 'vona-module-a-orm';
|
|
32
|
+
import { EntityStudent } from '../entity/student.ts';
|
|
33
|
+
|
|
34
|
+
@Model({ entity: EntityStudent })
|
|
35
|
+
export class ModelStudent extends BeanModelBase<EntityStudent> {}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The key relationship is that a model is bound to an entity and exposes ORM-oriented operations for that entity.
|
|
39
|
+
|
|
40
|
+
## Using a model
|
|
41
|
+
|
|
42
|
+
Using models in Vona supports both dependency injection and dependency lookup, but dependency lookup is usually the clearer default.
|
|
43
|
+
|
|
44
|
+
### Lookup in the current module
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
class ServiceStudent {
|
|
48
|
+
async findAll(): Promise<EntityStudent[]> {
|
|
49
|
+
return await this.scope.model.student.select();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Lookup across modules
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
class ServiceStudent {
|
|
58
|
+
async findAll(): Promise<EntityStudent[]> {
|
|
59
|
+
return await this.$scope.demoStudent.model.student.select();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Direct container access
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
class ServiceStudent {
|
|
68
|
+
async findAll(): Promise<EntityStudent[]> {
|
|
69
|
+
return await this.bean._getBean('demo-student.model.student').select();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This is one of the important backend layer boundaries:
|
|
75
|
+
|
|
76
|
+
- services should usually orchestrate through models
|
|
77
|
+
- models should remain the main persistence-facing abstraction instead of bypassing directly to ad hoc SQL everywhere
|
|
78
|
+
|
|
79
|
+
## Basic CRUD patterns
|
|
80
|
+
|
|
81
|
+
### Create
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
return await this.scope.model.student.insert(student);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Read
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
return await this.scope.model.student.select();
|
|
91
|
+
return await this.scope.model.student.getById(id);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Update
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
return await this.scope.model.student.updateById(id, student);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Delete
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
return await this.scope.model.student.deleteById(id);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
These methods are also part of the generated CRUD thread; see [CRUD Workflow](/backend/crud-workflow).
|
|
107
|
+
|
|
108
|
+
## Query-builder support
|
|
109
|
+
|
|
110
|
+
Vona models are built on Knex, so the model layer also supports lower-level query builder access when needed.
|
|
111
|
+
|
|
112
|
+
Representative patterns:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
this.scope.model.student.builder().where('name', 'tom').orderBy('name');
|
|
116
|
+
this.scope.model.student.builderSelect().where('name', 'tom').orderBy('name');
|
|
117
|
+
this.scope.model.student.query('select * from demoStudent');
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A practical rule is:
|
|
121
|
+
|
|
122
|
+
- prefer model methods and model-aware query paths first
|
|
123
|
+
- use builder or raw SQL only when the higher-level model surface is not enough
|
|
124
|
+
|
|
125
|
+
## Important model options
|
|
126
|
+
|
|
127
|
+
Several important model options include:
|
|
128
|
+
|
|
129
|
+
- `entity`
|
|
130
|
+
- `table`
|
|
131
|
+
- `disableDeleted`
|
|
132
|
+
- `disableInstance`
|
|
133
|
+
- `disableCreateTime`
|
|
134
|
+
- `disableUpdateTime`
|
|
135
|
+
- `softDeletionPrune`
|
|
136
|
+
- `client`
|
|
137
|
+
- `cache`
|
|
138
|
+
- `relations`
|
|
139
|
+
|
|
140
|
+
These options matter because Vona models are not only raw database adapters. They also carry framework-level behavior such as soft deletion, multi-instance support, datasource selection, caching, and relations.
|
|
141
|
+
|
|
142
|
+
## App-config overrides
|
|
143
|
+
|
|
144
|
+
Model options can also be configured in app config.
|
|
145
|
+
|
|
146
|
+
Representative pattern:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
config.onions = {
|
|
150
|
+
model: {
|
|
151
|
+
'demo-student:student': {
|
|
152
|
+
disableDeleted: true,
|
|
153
|
+
disableInstance: true,
|
|
154
|
+
client: 'mysql',
|
|
155
|
+
cache: false,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This is one of the key contract-loop ideas: model behavior is not defined only inside the model file. It can also be refined through project configuration.
|
|
162
|
+
|
|
163
|
+
## Dynamic table partitioning
|
|
164
|
+
|
|
165
|
+
Model supports dynamic table partitioning.
|
|
166
|
+
|
|
167
|
+
Representative pattern:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
@Model({
|
|
171
|
+
table: (ctx: VonaContext, where: EntityOrder | undefined, defaultTable: keyof ITableRecord) => {
|
|
172
|
+
return `${defaultTable}_${moment().format('YYYYMMDD')}`;
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
class ModelOrder {}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This matters because some persistence decisions belong at the model abstraction level even when they materially change how the table is resolved.
|
|
179
|
+
|
|
180
|
+
## Soft deletion and multi-instance defaults
|
|
181
|
+
|
|
182
|
+
By default, Vona models support:
|
|
183
|
+
|
|
184
|
+
- soft deletion
|
|
185
|
+
- multi-instance or multi-tenancy filtering
|
|
186
|
+
|
|
187
|
+
That means model behavior can be richer than a naïve SQL wrapper. For example, a normal `select()` already participates in instance filtering and deleted-record filtering unless configured otherwise.
|
|
188
|
+
|
|
189
|
+
A practical implication is:
|
|
190
|
+
|
|
191
|
+
- contract and test behavior should not assume raw-table semantics when the model layer is active
|
|
192
|
+
|
|
193
|
+
## Instance-aware model semantics
|
|
194
|
+
|
|
195
|
+
One important current-runtime distinction is that ordinary model usage is instance-aware by default.
|
|
196
|
+
|
|
197
|
+
A practical interpretation is:
|
|
198
|
+
|
|
199
|
+
- normal model operations participate in the current instance context
|
|
200
|
+
- instance-aware filtering is part of normal model behavior unless disabled
|
|
201
|
+
- request-scoped code should usually preserve that behavior instead of bypassing it casually
|
|
202
|
+
|
|
203
|
+
This is why `disableInstance` is a meaningful semantic choice rather than a minor ORM toggle.
|
|
204
|
+
|
|
205
|
+
Use it only when the model truly should ignore the active instance boundary.
|
|
206
|
+
|
|
207
|
+
Another practical implication is:
|
|
208
|
+
|
|
209
|
+
- lower-level builder or raw-SQL flows may need extra care when you are reproducing behavior that the ordinary model path would have applied automatically
|
|
210
|
+
|
|
211
|
+
For the broader instance/config story, also see [Config Guide](/backend/config-guide).
|
|
212
|
+
|
|
213
|
+
## Datasource selection
|
|
214
|
+
|
|
215
|
+
Vona supports `multi-database` and `multi-datasource` behavior at the model layer.
|
|
216
|
+
|
|
217
|
+
Representative modes include:
|
|
218
|
+
|
|
219
|
+
- default datasource
|
|
220
|
+
- static datasource in model options
|
|
221
|
+
- app-config datasource override
|
|
222
|
+
- adaptive datasource through a function
|
|
223
|
+
- dynamic datasource chosen in code with `newInstance(...)`
|
|
224
|
+
|
|
225
|
+
Representative dynamic pattern:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
const modelMysql = this.scope.model.student.newInstance('mysql');
|
|
229
|
+
return await modelMysql.select();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
This matters because backend contract behavior can depend on datasource choice, not just on query shape.
|
|
233
|
+
|
|
234
|
+
In the current runtime, datasource choice can also change indirectly through instance isolation. If the active instance is configured as isolated, the effective default datasource may switch through that instance’s `isolateClient` setting even when the calling code did not name a datasource explicitly.
|
|
235
|
+
|
|
236
|
+
That is why model behavior should be read together with:
|
|
237
|
+
|
|
238
|
+
- [Config Guide](/backend/config-guide)
|
|
239
|
+
- [Multi-Database and Datasource Guide](/backend/multi-database-datasource)
|
|
240
|
+
|
|
241
|
+
## Cache behavior
|
|
242
|
+
|
|
243
|
+
Vona models enable cache behavior by default.
|
|
244
|
+
|
|
245
|
+
A practical distinction is:
|
|
246
|
+
|
|
247
|
+
- entity cache stores entity records
|
|
248
|
+
- query cache stores query-derived entity id sets
|
|
249
|
+
|
|
250
|
+
That means model behavior affects performance and consistency semantics, not only data retrieval.
|
|
251
|
+
|
|
252
|
+
For the broader cache story, also see [Cache Guide](/backend/cache-guide).
|
|
253
|
+
|
|
254
|
+
## Relationship to the backend contract loop
|
|
255
|
+
|
|
256
|
+
Read this guide together with:
|
|
257
|
+
|
|
258
|
+
- [Service Guide](/backend/service-guide)
|
|
259
|
+
- [Entity Guide](/backend/entity-guide)
|
|
260
|
+
- [DTO Guide](/backend/dto-guide)
|
|
261
|
+
- [OpenAPI Guide](/backend/openapi-guide)
|
|
262
|
+
- [CRUD Workflow](/backend/crud-workflow)
|
|
263
|
+
- [Migration and Changes](/backend/migration-and-changes)
|
|
264
|
+
|
|
265
|
+
## Implementation checks for model-layer changes
|
|
266
|
+
|
|
267
|
+
When creating backend persistence logic:
|
|
268
|
+
|
|
269
|
+
1. start from the model and entity pairing
|
|
270
|
+
2. prefer model methods and model-aware query paths
|
|
271
|
+
3. preserve Vona soft-delete and instance-aware behavior unless there is a real reason not to
|
|
272
|
+
4. choose deliberately among local scope, cross-module scope, and direct bean access
|
|
273
|
+
5. remember that datasource, cache, and model options can change the behavior of the backend contract loop
|
|
274
|
+
6. drop to raw SQL or lower-level query builder logic only when the higher-level model surface is insufficient
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Multi-Database and Datasource Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how multi-database and multi-datasource support works in Vona within the Cabloy monorepo.
|
|
4
|
+
|
|
5
|
+
## Why this matters
|
|
6
|
+
|
|
7
|
+
Vona ORM is designed for business systems that may need:
|
|
8
|
+
|
|
9
|
+
- multiple database engines
|
|
10
|
+
- multiple datasources
|
|
11
|
+
- cross-datasource relation queries
|
|
12
|
+
- datasource-aware topology decisions
|
|
13
|
+
- isolated-instance database routing
|
|
14
|
+
|
|
15
|
+
This is an important part of the framework’s large-system positioning.
|
|
16
|
+
|
|
17
|
+
## Core model
|
|
18
|
+
|
|
19
|
+
A representative example uses related models such as `User` and `Order`.
|
|
20
|
+
|
|
21
|
+
The key idea is that model relations can remain meaningful even when the participating data lives on different datasources.
|
|
22
|
+
|
|
23
|
+
## Datasource setup
|
|
24
|
+
|
|
25
|
+
Three important pieces define the datasource setup:
|
|
26
|
+
|
|
27
|
+
1. datasource type definitions
|
|
28
|
+
2. datasource configuration in app config
|
|
29
|
+
3. model or relation-level selection of which datasource to use
|
|
30
|
+
|
|
31
|
+
That means datasource choice is part of the typed application model, not just a hidden runtime string.
|
|
32
|
+
|
|
33
|
+
## Default datasource selection
|
|
34
|
+
|
|
35
|
+
In the current runtime, ordinary datasource selection starts from `config.database.defaultClient`.
|
|
36
|
+
|
|
37
|
+
A practical order is:
|
|
38
|
+
|
|
39
|
+
1. use the explicitly requested datasource when one is provided
|
|
40
|
+
2. otherwise fall back to the configured default datasource
|
|
41
|
+
3. if the current instance is isolated, allow the instance’s `isolateClient` to override the ordinary default
|
|
42
|
+
|
|
43
|
+
This is why datasource selection belongs partly to config and partly to request/runtime context.
|
|
44
|
+
|
|
45
|
+
## Explicit client selection
|
|
46
|
+
|
|
47
|
+
One pattern is to create a model instance bound to a chosen datasource dynamically.
|
|
48
|
+
|
|
49
|
+
Representative pattern:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const modelMysql = this.scope.model.student.newInstance('mysql');
|
|
53
|
+
return await modelMysql.select();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This is useful when the decision is explicit in business logic rather than implied by config defaults.
|
|
57
|
+
|
|
58
|
+
## Model-level, relation-level, and app-config-level defaults
|
|
59
|
+
|
|
60
|
+
You can simplify ordinary usage by declaring datasource choices in:
|
|
61
|
+
|
|
62
|
+
- model options
|
|
63
|
+
- relation options
|
|
64
|
+
- app config
|
|
65
|
+
|
|
66
|
+
That reduces repeated dynamic selection in ordinary business code.
|
|
67
|
+
|
|
68
|
+
A practical distinction is:
|
|
69
|
+
|
|
70
|
+
- use model or app-config defaults when one datasource should usually win
|
|
71
|
+
- use relation metadata when different parts of a graph need different datasources
|
|
72
|
+
- use explicit runtime selection when the current task truly needs to choose in code
|
|
73
|
+
|
|
74
|
+
## Ordinary multi-datasource behavior vs isolated-instance routing
|
|
75
|
+
|
|
76
|
+
One of the most important backend distinctions is:
|
|
77
|
+
|
|
78
|
+
- **ordinary multi-datasource behavior** chooses among datasources for business or topology reasons
|
|
79
|
+
- **isolated-instance routing** changes the effective default datasource because the active instance is configured as isolated
|
|
80
|
+
|
|
81
|
+
In the current repo, an isolated instance can declare:
|
|
82
|
+
|
|
83
|
+
- `isolate: true`
|
|
84
|
+
- `isolateClient: 'isolateTest'`
|
|
85
|
+
|
|
86
|
+
That means a request can remain model-native while still landing on a different default datasource because of instance configuration.
|
|
87
|
+
|
|
88
|
+
## Instance-aware database strategy
|
|
89
|
+
|
|
90
|
+
This matters because backend database strategy is not only about choosing MySQL vs PostgreSQL vs Sqlite3.
|
|
91
|
+
|
|
92
|
+
It is also about deciding whether:
|
|
93
|
+
|
|
94
|
+
- all instances share one datasource layout
|
|
95
|
+
- some instances share data while others isolate storage
|
|
96
|
+
- a test or tenant-specific instance should use a dedicated client
|
|
97
|
+
|
|
98
|
+
A practical example in the current repo is the `isolateTest` client used together with an isolated test instance.
|
|
99
|
+
|
|
100
|
+
## Concrete isolated datasource pattern in this repo
|
|
101
|
+
|
|
102
|
+
In the current app config, `isolateTest` is created by cloning the currently selected default client into a dedicated isolated client slot.
|
|
103
|
+
|
|
104
|
+
That pattern matters because it shows that isolated-instance routing does not require a completely separate datasource architecture from day one. It can start from the ordinary default client and then create an isolated variant for instance-aware routing.
|
|
105
|
+
|
|
106
|
+
A practical runtime split in the current repo is:
|
|
107
|
+
|
|
108
|
+
- base config defines `isolateTest` from the current default client
|
|
109
|
+
- dev/test config enables an isolated instance that points at `isolateClient: 'isolateTest'`
|
|
110
|
+
- prod config can explicitly unset `isolateTest` when that isolated test-oriented client should not remain active
|
|
111
|
+
|
|
112
|
+
## Relation-level datasource selection
|
|
113
|
+
|
|
114
|
+
Relation options can also specify datasource metadata.
|
|
115
|
+
|
|
116
|
+
That matters because different parts of a related object graph may need different datasource bindings.
|
|
117
|
+
|
|
118
|
+
## Datasource levels and execution isolation
|
|
119
|
+
|
|
120
|
+
Datasource architecture is not only about routing to the right database. It is also about isolation across execution contexts.
|
|
121
|
+
|
|
122
|
+
In distributed flows such as `pushAsync`, Vona can move work to a higher datasource level so background execution does not contend with the current request context for the same constrained connection pool.
|
|
123
|
+
|
|
124
|
+
That is why datasource design should be read together with:
|
|
125
|
+
|
|
126
|
+
- queue behavior
|
|
127
|
+
- transaction behavior
|
|
128
|
+
- relation loading
|
|
129
|
+
- runtime and distributed execution patterns
|
|
130
|
+
|
|
131
|
+
## Topology guidance
|
|
132
|
+
|
|
133
|
+
A practical way to think about topology is:
|
|
134
|
+
|
|
135
|
+
- use ordinary datasource selection for routine multi-datasource routing
|
|
136
|
+
- use isolated-instance config when the default database route should vary by instance
|
|
137
|
+
- use relation metadata when cross-datasource object graphs must still feel model-native
|
|
138
|
+
- use explicit runtime selection when business flow must choose a datasource directly
|
|
139
|
+
- escalate to sharding or deeper Cabloy architecture when the problem is no longer just datasource choice but data-distribution design
|
|
140
|
+
|
|
141
|
+
## Relationship to config, model, and dynamic datasource
|
|
142
|
+
|
|
143
|
+
Read this guide together with:
|
|
144
|
+
|
|
145
|
+
- [Config Guide](/backend/config-guide)
|
|
146
|
+
- [Runtime and Flavors](/backend/runtime-and-flavors)
|
|
147
|
+
- [Model Guide](/backend/model-guide)
|
|
148
|
+
- [Dynamic Datasource Guide](/backend/dynamic-datasource-guide)
|
|
149
|
+
- [Sharding Guide](/backend/sharding-guide)
|
|
150
|
+
- [Queue Guide](/backend/queue-guide)
|
|
151
|
+
- [Relations Guide](/backend/relations-guide)
|
|
152
|
+
|
|
153
|
+
A practical split is:
|
|
154
|
+
|
|
155
|
+
- this guide explains ordinary multi-database and multi-datasource behavior
|
|
156
|
+
- config and instance docs explain why the effective default may differ by runtime or instance
|
|
157
|
+
- the dynamic datasource guide points to deeper routing architecture
|
|
158
|
+
- the sharding guide points to deeper data-distribution architecture
|
|
159
|
+
|
|
160
|
+
## Implementation checks for multi-datasource changes
|
|
161
|
+
|
|
162
|
+
When changing backend data flow in a multi-datasource system, ask:
|
|
163
|
+
|
|
164
|
+
1. is the model using an explicit datasource, a model default, or the current effective default datasource?
|
|
165
|
+
2. does the active instance change that default through `isolateClient`?
|
|
166
|
+
3. do related models need different datasource bindings?
|
|
167
|
+
4. should the datasource choice live in runtime logic, relation metadata, model metadata, or app config?
|
|
168
|
+
5. does the transaction, queue, or cache path need to match the same datasource choice?
|
|
169
|
+
6. is the problem still ordinary datasource routing, or has it become a dynamic-datasource or sharding concern?
|
|
170
|
+
|
|
171
|
+
That keeps multi-datasource logic coherent instead of fragile.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Multi-Instance and Instance Resolution
|
|
2
|
+
|
|
3
|
+
This guide explains how multi-instance behavior works in Vona within the Cabloy monorepo.
|
|
4
|
+
|
|
5
|
+
## Why this matters
|
|
6
|
+
|
|
7
|
+
In Vona, backend runtime behavior is not always global-only.
|
|
8
|
+
|
|
9
|
+
A backend application may need:
|
|
10
|
+
|
|
11
|
+
- a shared default instance
|
|
12
|
+
- named instances for tenant-like separation
|
|
13
|
+
- isolated instances with their own datasource routing
|
|
14
|
+
- instance-aware config, startup, and model behavior
|
|
15
|
+
|
|
16
|
+
That is why multi-instance behavior should be understood as part of the backend runtime/config family, not only as an ORM detail.
|
|
17
|
+
|
|
18
|
+
## Three practical layers
|
|
19
|
+
|
|
20
|
+
A useful mental model is:
|
|
21
|
+
|
|
22
|
+
- runtime and config decide how instances are declared
|
|
23
|
+
- request context decides which instance is active
|
|
24
|
+
- model and datasource behavior decide how that instance affects persistence
|
|
25
|
+
|
|
26
|
+
## Instance config shape
|
|
27
|
+
|
|
28
|
+
In the current runtime, instance behavior is configured under `config.instance`.
|
|
29
|
+
|
|
30
|
+
Representative shape:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
config.instance = {
|
|
34
|
+
getInstanceName: undefined,
|
|
35
|
+
queryField: $protocolKey('x-vona-instance-name'),
|
|
36
|
+
headerField: $protocolKey('x-vona-instance-name'),
|
|
37
|
+
instances: {
|
|
38
|
+
'': { password: '', title: '' },
|
|
39
|
+
'shareTest': { password: '', title: '' },
|
|
40
|
+
'isolateTest': {
|
|
41
|
+
password: '',
|
|
42
|
+
title: '',
|
|
43
|
+
id: 1000,
|
|
44
|
+
isolate: true,
|
|
45
|
+
isolateClient: 'isolateTest',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The important fields are:
|
|
52
|
+
|
|
53
|
+
- `getInstanceName`
|
|
54
|
+
- `queryField`
|
|
55
|
+
- `headerField`
|
|
56
|
+
- `instances`
|
|
57
|
+
- per-instance options such as `id`, `isolate`, `isolateClient`, and `config`
|
|
58
|
+
|
|
59
|
+
## Shared instance vs isolated instance
|
|
60
|
+
|
|
61
|
+
A practical distinction is:
|
|
62
|
+
|
|
63
|
+
- a **shared** instance participates in the normal shared datasource strategy
|
|
64
|
+
- an **isolated** instance can route to its own datasource through `isolateClient`
|
|
65
|
+
|
|
66
|
+
This means multi-instance behavior is not only a naming concern. It can materially change which database path the backend uses.
|
|
67
|
+
|
|
68
|
+
## How the active instance name is resolved
|
|
69
|
+
|
|
70
|
+
In the current runtime, the instance name is resolved in this order:
|
|
71
|
+
|
|
72
|
+
1. `getInstanceName(ctx)` if provided
|
|
73
|
+
2. the configured query field
|
|
74
|
+
3. the configured header field
|
|
75
|
+
4. subdomain-derived instance name
|
|
76
|
+
|
|
77
|
+
This matters because request routing, config, and datasource behavior may all depend on the resolved instance name.
|
|
78
|
+
|
|
79
|
+
A special case is also supported:
|
|
80
|
+
|
|
81
|
+
- `'null'` is normalized to `null`
|
|
82
|
+
|
|
83
|
+
A practical fallback rule is:
|
|
84
|
+
|
|
85
|
+
- subdomain-based instance resolution only becomes relevant if custom getter, query-field, and header-field resolution did not already determine the instance name
|
|
86
|
+
|
|
87
|
+
## Instance edge cases to remember
|
|
88
|
+
|
|
89
|
+
A few current-runtime edge cases are worth remembering:
|
|
90
|
+
|
|
91
|
+
- disabled instances can be declared with `false`
|
|
92
|
+
- isolated instances require an explicit `id`
|
|
93
|
+
- instance-name resolution is cached on the current context once determined
|
|
94
|
+
- the instance record can be created or refreshed through the instance service before the effective config is cached
|
|
95
|
+
|
|
96
|
+
## What context exposes
|
|
97
|
+
|
|
98
|
+
Once instance resolution is active, the request context can expose:
|
|
99
|
+
|
|
100
|
+
- `ctx.instanceName`
|
|
101
|
+
- `ctx.instance`
|
|
102
|
+
- `ctx.config`
|
|
103
|
+
|
|
104
|
+
A practical distinction is:
|
|
105
|
+
|
|
106
|
+
- `ctx.instanceName` identifies the active instance
|
|
107
|
+
- `ctx.instance` is the loaded instance record
|
|
108
|
+
- `ctx.config` is the effective config merged for that instance-aware context
|
|
109
|
+
|
|
110
|
+
That means request-scoped backend code can stay instance-aware without manually reassembling config or routing rules.
|
|
111
|
+
|
|
112
|
+
## How instance config affects effective backend config
|
|
113
|
+
|
|
114
|
+
This page owns the request-context and instance-aware merge view. For env-file precedence and mode/flavor selection, see [Runtime and Flavors](/backend/runtime-and-flavors). For the broader config-layering surface, see [Config Guide](/backend/config-guide).
|
|
115
|
+
|
|
116
|
+
In the current runtime, instance-aware config is built by merging:
|
|
117
|
+
|
|
118
|
+
1. `app.config`
|
|
119
|
+
2. static config under `config.instance.instances[instanceName].config`
|
|
120
|
+
3. any persisted config stored on the instance record
|
|
121
|
+
|
|
122
|
+
This is why instance behavior belongs partly to config docs and partly to runtime docs.
|
|
123
|
+
|
|
124
|
+
A practical merge-order mental model is:
|
|
125
|
+
|
|
126
|
+
1. start from `app.config`
|
|
127
|
+
2. merge static instance config from `config.instance.instances[instanceName].config`
|
|
128
|
+
3. merge persisted config stored on the instance record
|
|
129
|
+
4. expose the result through `ctx.config`
|
|
130
|
+
|
|
131
|
+
For the broader config-layering story, also see [Config Guide](/backend/config-guide).
|
|
132
|
+
|
|
133
|
+
## How instance affects startup behavior
|
|
134
|
+
|
|
135
|
+
Startup is also instance-aware.
|
|
136
|
+
|
|
137
|
+
A practical split is:
|
|
138
|
+
|
|
139
|
+
- app startup handles backend-wide initialization
|
|
140
|
+
- instance startup handles per-instance initialization after the app is ready for instances
|
|
141
|
+
|
|
142
|
+
In the current runtime:
|
|
143
|
+
|
|
144
|
+
- `test` and `dev` eagerly start the default instance
|
|
145
|
+
- production-style flows iterate configured static instances
|
|
146
|
+
- instance startup work is queued and coordinated so one instance can initialize cleanly
|
|
147
|
+
|
|
148
|
+
For the lifecycle view, also see [Backend Startup Guide](/backend/startup-guide).
|
|
149
|
+
|
|
150
|
+
## How instance affects datasource selection
|
|
151
|
+
|
|
152
|
+
One of the most important multi-instance consequences is datasource routing.
|
|
153
|
+
|
|
154
|
+
In the current runtime, datasource selection can work like this:
|
|
155
|
+
|
|
156
|
+
1. use an explicit datasource when code names one
|
|
157
|
+
2. otherwise use the configured default datasource
|
|
158
|
+
3. if the active instance is isolated, let `isolateClient` override that default
|
|
159
|
+
|
|
160
|
+
This is why instance isolation should be understood together with datasource strategy rather than documented as an unrelated feature.
|
|
161
|
+
|
|
162
|
+
For the datasource view, also see [Multi-Database and Datasource Guide](/backend/multi-database-datasource).
|
|
163
|
+
|
|
164
|
+
## How instance affects model behavior
|
|
165
|
+
|
|
166
|
+
Ordinary model operations are instance-aware by default.
|
|
167
|
+
|
|
168
|
+
That means:
|
|
169
|
+
|
|
170
|
+
- normal model flows participate in instance filtering
|
|
171
|
+
- instance-aware config and startup can influence model behavior indirectly
|
|
172
|
+
- `disableInstance` changes semantics and should be used deliberately
|
|
173
|
+
|
|
174
|
+
For the model-layer perspective, also see [Model Guide](/backend/model-guide).
|
|
175
|
+
|
|
176
|
+
## Relationship to runtime and config docs
|
|
177
|
+
|
|
178
|
+
Read this guide together with:
|
|
179
|
+
|
|
180
|
+
- [Runtime and Flavors](/backend/runtime-and-flavors)
|
|
181
|
+
- [Config Guide](/backend/config-guide)
|
|
182
|
+
- [Backend Startup Guide](/backend/startup-guide)
|
|
183
|
+
- [Model Guide](/backend/model-guide)
|
|
184
|
+
- [Multi-Database and Datasource Guide](/backend/multi-database-datasource)
|
|
185
|
+
|
|
186
|
+
## Implementation checks for instance-resolution changes
|
|
187
|
+
|
|
188
|
+
When editing backend runtime, datasource, or tenant-like behavior, ask:
|
|
189
|
+
|
|
190
|
+
1. how is the current instance name resolved?
|
|
191
|
+
2. is the task about shared-instance behavior or isolated-instance behavior?
|
|
192
|
+
3. should the logic read `app.config` or `ctx.config`?
|
|
193
|
+
4. does instance startup or instance config need to change as well?
|
|
194
|
+
5. does datasource routing change indirectly through `isolateClient` even if no model call names a client explicitly?
|
|
195
|
+
|
|
196
|
+
That keeps multi-instance behavior aligned with the current Vona runtime rather than treating it as a loose convention.
|