cabloy 5.1.60 → 5.1.62
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/hooks/contract-loop-gate.ts +296 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/cabloy-backend-scaffold/SKILL.md +2 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -0
- package/.claude/skills/cabloy-contract-loop/SKILL.md +89 -16
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
- package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
- package/.claude/skills/cabloy-domain-planning/SKILL.md +212 -0
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -0
- package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
- package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +7 -0
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
- package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
- package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
- package/CHANGELOG.md +64 -0
- package/CLAUDE.md +11 -0
- package/cabloy-docs/.vitepress/config.mjs +197 -5
- package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +22 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +12 -7
- package/cabloy-docs/ai/introduction.md +1 -0
- package/cabloy-docs/ai/playbook-backend-module.md +6 -0
- package/cabloy-docs/ai/playbook-module-removal.md +164 -0
- package/cabloy-docs/ai/skills.md +12 -0
- package/cabloy-docs/backend/backend-contract-emission-output-inspection.md +189 -0
- package/cabloy-docs/backend/backend-contract-emission-source-reading-map.md +160 -0
- package/cabloy-docs/backend/backend-contract-emission-specimen.md +170 -0
- package/cabloy-docs/backend/backend-resource-module-contract-chain.md +323 -0
- package/cabloy-docs/backend/backend-source-reading-debug-checklist.md +173 -0
- package/cabloy-docs/backend/backend-source-reading-roadmap.md +129 -0
- package/cabloy-docs/backend/backend-source-reading-verify-playbook.md +166 -0
- package/cabloy-docs/backend/bean-scene-authoring.md +4 -4
- package/cabloy-docs/backend/broadcast-guide.md +3 -3
- package/cabloy-docs/backend/cli.md +20 -11
- package/cabloy-docs/backend/config-guide.md +4 -4
- package/cabloy-docs/backend/controller-aop-guide.md +10 -10
- package/cabloy-docs/backend/controller-guide.md +12 -2
- package/cabloy-docs/backend/crud-workflow.md +7 -3
- package/cabloy-docs/backend/dto-guide.md +18 -2
- package/cabloy-docs/backend/dto-infer-generation.md +201 -25
- package/cabloy-docs/backend/election-guide.md +2 -2
- package/cabloy-docs/backend/entity-guide.md +30 -3
- package/cabloy-docs/backend/error-guide.md +3 -3
- package/cabloy-docs/backend/event-guide.md +4 -4
- package/cabloy-docs/backend/external-aop-guide.md +2 -2
- package/cabloy-docs/backend/field-indexes.md +9 -3
- package/cabloy-docs/backend/foundation.md +8 -8
- package/cabloy-docs/backend/i18n-guide.md +6 -6
- package/cabloy-docs/backend/internal-aop-guide.md +2 -2
- package/cabloy-docs/backend/introduction.md +15 -0
- package/cabloy-docs/backend/migration-and-changes.md +3 -3
- package/cabloy-docs/backend/model-guide.md +16 -6
- package/cabloy-docs/backend/openapi-guide.md +3 -0
- package/cabloy-docs/backend/queue-guide.md +3 -3
- package/cabloy-docs/backend/redlock-guide.md +2 -2
- package/cabloy-docs/backend/schedule-guide.md +2 -2
- package/cabloy-docs/backend/scripts.md +8 -0
- package/cabloy-docs/backend/serialization-guide.md +12 -2
- package/cabloy-docs/backend/service-guide.md +18 -9
- package/cabloy-docs/backend/startup-guide.md +5 -5
- package/cabloy-docs/backend/status-guide.md +271 -0
- package/cabloy-docs/backend/unit-testing.md +3 -3
- package/cabloy-docs/backend/vona-source-reading-map.md +157 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +5 -5
- package/cabloy-docs/backend/websocket-usage-guide.md +15 -8
- package/cabloy-docs/frontend/a-model-under-the-hood.md +281 -0
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +248 -0
- package/cabloy-docs/frontend/a-router-guide.md +307 -0
- package/cabloy-docs/frontend/api-guide.md +6 -4
- package/cabloy-docs/frontend/api-schema-guide.md +1 -0
- package/cabloy-docs/frontend/app-startup-guide.md +7 -4
- package/cabloy-docs/frontend/bean-scene-authoring.md +3 -1
- package/cabloy-docs/frontend/behavior-guide.md +16 -16
- package/cabloy-docs/frontend/cli.md +14 -2
- package/cabloy-docs/frontend/command-scene-authoring.md +504 -0
- package/cabloy-docs/frontend/component-guide.md +5 -5
- package/cabloy-docs/frontend/component-props-guide.md +1 -1
- package/cabloy-docs/frontend/component-v-model-guide.md +2 -2
- package/cabloy-docs/frontend/design-principles.md +6 -0
- package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
- package/cabloy-docs/frontend/filter-query-select-data-flow-guide.md +260 -0
- package/cabloy-docs/frontend/form-guide.md +786 -0
- package/cabloy-docs/frontend/form-scene-to-page-meta-guide.md +303 -0
- package/cabloy-docs/frontend/foundation.md +33 -0
- package/cabloy-docs/frontend/frontend-source-reading-roadmap.md +249 -0
- package/cabloy-docs/frontend/generated-contract-consumption-debug-checklist.md +190 -0
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +205 -0
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +157 -0
- package/cabloy-docs/frontend/generated-contract-consumption-specimen.md +203 -0
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +189 -0
- package/cabloy-docs/frontend/generic-component-guide.md +1 -1
- package/cabloy-docs/frontend/introduction.md +38 -5
- package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
- package/cabloy-docs/frontend/mock-guide.md +1 -0
- package/cabloy-docs/frontend/model-architecture.md +288 -39
- package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
- package/cabloy-docs/frontend/model-resource-cookbook.md +508 -0
- package/cabloy-docs/frontend/model-resource-internals-deep-dive.md +238 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +402 -0
- package/cabloy-docs/frontend/model-resource-usage-guide.md +334 -0
- package/cabloy-docs/frontend/model-state-guide.md +371 -15
- package/cabloy-docs/frontend/module-scope.md +8 -8
- package/cabloy-docs/frontend/modules-and-suites.md +2 -1
- package/cabloy-docs/frontend/navigation-guards-guide.md +7 -0
- package/cabloy-docs/frontend/openapi-sdk-guide.md +17 -6
- package/cabloy-docs/frontend/page-guide.md +15 -9
- package/cabloy-docs/frontend/page-meta-guide.md +466 -0
- package/cabloy-docs/frontend/page-params-guide.md +3 -3
- package/cabloy-docs/frontend/page-query-guide.md +2 -2
- package/cabloy-docs/frontend/page-route-guide.md +6 -0
- package/cabloy-docs/frontend/permission-formscene-action-visibility-guide.md +263 -0
- package/cabloy-docs/frontend/quickstart.md +18 -2
- package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +271 -0
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +279 -0
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +522 -0
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +622 -0
- package/cabloy-docs/frontend/root-behaviors-guide.md +282 -0
- package/cabloy-docs/frontend/route-alias-guide.md +6 -0
- package/cabloy-docs/frontend/router-stack-guide.md +229 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +26 -3
- package/cabloy-docs/frontend/router-tabs-layout-integration.md +367 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +6 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +7 -0
- package/cabloy-docs/frontend/router-tabs-vs-stack.md +167 -0
- package/cabloy-docs/frontend/router-view-hosts-guide.md +450 -0
- package/cabloy-docs/frontend/server-data.md +4 -1
- package/cabloy-docs/frontend/system-startup-guide.md +2 -2
- package/cabloy-docs/frontend/table-action-visibility-permission-flow-guide.md +263 -0
- package/cabloy-docs/frontend/table-cell-cookbook.md +568 -0
- package/cabloy-docs/frontend/table-guide.md +373 -0
- package/cabloy-docs/frontend/table-resource-crud-cookbook.md +496 -0
- package/cabloy-docs/frontend/zova-app-guide.md +251 -0
- package/cabloy-docs/frontend/zova-form-source-reading-map.md +293 -0
- package/cabloy-docs/frontend/zova-form-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-source-reading-map.md +421 -0
- package/cabloy-docs/frontend/zova-table-controller-render-supplement.md +225 -0
- package/cabloy-docs/frontend/zova-table-source-reading-map.md +317 -0
- package/cabloy-docs/frontend/zova-table-under-the-hood.md +532 -0
- package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist.md +245 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map.md +139 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook.md +248 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions.md +511 -0
- package/cabloy-docs/fullstack/contract-loop-playbook.md +356 -0
- package/cabloy-docs/fullstack/edition-collaboration-differences.md +6 -0
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +199 -23
- package/cabloy-docs/fullstack/introduction.md +15 -1
- package/cabloy-docs/fullstack/openapi-to-sdk.md +135 -11
- package/cabloy-docs/fullstack/suites-and-modules.md +333 -0
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +3 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +4 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +6 -2
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +60 -23
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +14 -7
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +6 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +17 -4
- package/cabloy-docs/reference/bean-scene-boilerplates.md +15 -13
- package/cabloy-docs/reference/package-map.md +4 -3
- package/package.json +2 -1
- package/scripts/init.ts +2 -18
- package/scripts/initTestData.ts +25 -0
- package/scripts/upgrade.ts +17 -2
- package/vona/pnpm-lock.yaml +48 -194
- package/vona/src/suite/a-training/modules/training-student/package.json +53 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +400 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +18 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +12 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +21 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/ssrMenu.student.ts +29 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +74 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectReq.tsx +44 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectRes.tsx +11 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +45 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +42 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +25 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +84 -0
- package/vona/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +10 -0
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +57 -0
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +173 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.build.json +11 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.json +7 -0
- package/vona/src/suite/a-training/package.json +12 -0
- package/vona/src/suite/a-training/tsconfig.base.json +4 -0
- package/vona/src/suite/a-training/tsconfig.json +10 -0
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +416 -690
- package/zova/src/suite/a-training/modules/training-student/cli/openapi.config.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/package.json +52 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/component/formFieldLevel.ts +31 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +258 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +196 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +4146 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +151 -0
- package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +43 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionDeleteForce.tsx +51 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +56 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.level.tsx +63 -0
- package/zova/src/suite/a-training/modules/training-student/src/component/formFieldLevel/controller.tsx +117 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +42 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.build.json +13 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.json +5 -0
- package/zova/src/suite/a-training/package.json +12 -0
- package/zova/src/suite/a-training/tsconfig.base.json +4 -0
- package/zova/src/suite/a-training/tsconfig.json +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +29 -7
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/select/controller.tsx +34 -11
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +3 -3
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/lib/tableCell.ts +1 -1
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, statSync, writeFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { spawnSync, type SpawnSyncReturns } from 'node:child_process';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
interface HookPayload {
|
|
9
|
+
tool_input?: {
|
|
10
|
+
file_path?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface AnalysisResult {
|
|
15
|
+
forwardReason: string | null;
|
|
16
|
+
reverseReason: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface SyncStateEntry {
|
|
20
|
+
fingerprint: string;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type SyncState = Record<string, SyncStateEntry>;
|
|
25
|
+
|
|
26
|
+
const SCRIPT_FILE = fileURLToPath(import.meta.url);
|
|
27
|
+
const ROOT = path.resolve(path.dirname(SCRIPT_FILE), '../..');
|
|
28
|
+
const ROOT_KEY = toPosixPath(ROOT);
|
|
29
|
+
const STATE_FILE = path.join(os.tmpdir(), 'cabloy-contract-loop-gate-state.json');
|
|
30
|
+
const AUTO_SYNC_WINDOW_SECONDS = 300;
|
|
31
|
+
|
|
32
|
+
const TARGET_PATTERNS: Array<readonly [string, string]> = [
|
|
33
|
+
['zova/src/module/', '.ts'],
|
|
34
|
+
['zova/src/module/', '.tsx'],
|
|
35
|
+
['zova/src/module/', '.jsx'],
|
|
36
|
+
['zova/src/suite/', '.ts'],
|
|
37
|
+
['zova/src/suite/', '.tsx'],
|
|
38
|
+
['zova/src/suite/', '.jsx'],
|
|
39
|
+
['vona/src/', '.ts'],
|
|
40
|
+
['vona/src/', '.tsx'],
|
|
41
|
+
['vona/src/', '.jsx'],
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const FORWARD_PATH_MARKERS = ['/controller/', '/dto/', '/entity/'];
|
|
45
|
+
|
|
46
|
+
const FORWARD_CONTENT_MARKERS = ['@Web.', '@Api.field', '@Api.body', 'v.openapi(', '@Dto<'];
|
|
47
|
+
|
|
48
|
+
const REVERSE_VONA_CONTENT_MARKERS = [
|
|
49
|
+
'zova-rest-cabloy-basic-admin',
|
|
50
|
+
'ZovaRender.',
|
|
51
|
+
'tableActionRow(',
|
|
52
|
+
'tableActionBulk(',
|
|
53
|
+
'ZovaRender.field(',
|
|
54
|
+
'ZovaRender.cell(',
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const REVERSE_ZOVA_PATH_MARKERS = ['/src/bean/', '/src/component/', '/src/.metadata/'];
|
|
58
|
+
|
|
59
|
+
const REVERSE_ZOVA_CONTENT_MARKERS = [
|
|
60
|
+
"declare module 'zova-module-a-openapi'",
|
|
61
|
+
'IResourceTableActionRowRecord',
|
|
62
|
+
'@TableCell<',
|
|
63
|
+
'@Component(',
|
|
64
|
+
'@Component<',
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
function toPosixPath(value: string): string {
|
|
68
|
+
return value.split(path.sep).join('/');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizePath(value?: string): string | null {
|
|
72
|
+
if (!value) return null;
|
|
73
|
+
try {
|
|
74
|
+
const candidate = path.isAbsolute(value) ? value : path.join(ROOT, value);
|
|
75
|
+
return toPosixPath(path.resolve(candidate));
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isCodeFile(filePath: string): boolean {
|
|
82
|
+
return TARGET_PATTERNS.some(([prefix, suffix]) => filePath.includes(prefix) && filePath.endsWith(suffix));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function containsAny(text: string, needles: readonly string[]): boolean {
|
|
86
|
+
return needles.some(needle => text.includes(needle));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function pathContainsAny(filePath: string, needles: readonly string[]): boolean {
|
|
90
|
+
return needles.some(needle => filePath.includes(needle));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function detectForward(filePath: string, content: string): string | null {
|
|
94
|
+
if (!filePath.includes('/vona/src/')) return null;
|
|
95
|
+
if (pathContainsAny(filePath, FORWARD_PATH_MARKERS) || containsAny(content, FORWARD_CONTENT_MARKERS)) {
|
|
96
|
+
return 'Backend contract source may have changed.';
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function detectReverse(filePath: string, content: string): string | null {
|
|
102
|
+
if (filePath.includes('/vona/src/') && containsAny(content, REVERSE_VONA_CONTENT_MARKERS)) {
|
|
103
|
+
return 'Vona code is consuming frontend metadata or render resources.';
|
|
104
|
+
}
|
|
105
|
+
if (
|
|
106
|
+
filePath.includes('/zova/src/') &&
|
|
107
|
+
(pathContainsAny(filePath, REVERSE_ZOVA_PATH_MARKERS) ||
|
|
108
|
+
containsAny(content, REVERSE_ZOVA_CONTENT_MARKERS))
|
|
109
|
+
) {
|
|
110
|
+
return 'Frontend-owned resources or metadata may affect backend consumers.';
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function analyze(filePath: string, content: string): AnalysisResult {
|
|
116
|
+
return {
|
|
117
|
+
forwardReason: detectForward(filePath, content),
|
|
118
|
+
reverseReason: detectReverse(filePath, content),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hasSignal(result: AnalysisResult): boolean {
|
|
123
|
+
return Boolean(result.forwardReason || result.reverseReason);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isHighConfidenceReverseSource(filePath: string): boolean {
|
|
127
|
+
return filePath.includes('/zova/src/') && pathContainsAny(filePath, REVERSE_ZOVA_PATH_MARKERS);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function readText(filePath: string): string | null {
|
|
131
|
+
try {
|
|
132
|
+
return readFileSync(filePath, 'utf8');
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function loadState(): SyncState {
|
|
139
|
+
if (!existsSync(STATE_FILE)) return {};
|
|
140
|
+
try {
|
|
141
|
+
return JSON.parse(readFileSync(STATE_FILE, 'utf8')) as SyncState;
|
|
142
|
+
} catch {
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function saveState(state: SyncState): void {
|
|
148
|
+
try {
|
|
149
|
+
writeFileSync(STATE_FILE, JSON.stringify(state), 'utf8');
|
|
150
|
+
} catch {
|
|
151
|
+
// ignore state persistence failures
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function syncFingerprint(filePath: string): string {
|
|
156
|
+
try {
|
|
157
|
+
const stats = statSync(filePath, { bigint: true });
|
|
158
|
+
return `${filePath}:${stats.mtimeNs.toString()}`;
|
|
159
|
+
} catch {
|
|
160
|
+
return filePath;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function shouldSkipAutoSync(filePath: string): boolean {
|
|
165
|
+
const state = loadState();
|
|
166
|
+
const fingerprint = syncFingerprint(filePath);
|
|
167
|
+
const entry = state[ROOT_KEY];
|
|
168
|
+
if (!entry) return false;
|
|
169
|
+
if (entry.fingerprint !== fingerprint) return false;
|
|
170
|
+
if (Date.now() - entry.timestamp > AUTO_SYNC_WINDOW_SECONDS * 1000) return false;
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function markAutoSync(filePath: string): void {
|
|
175
|
+
const state = loadState();
|
|
176
|
+
state[ROOT_KEY] = {
|
|
177
|
+
fingerprint: syncFingerprint(filePath),
|
|
178
|
+
timestamp: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
saveState(state);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function runNpm(args: string[]): SpawnSyncReturns<string> {
|
|
184
|
+
const command = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
185
|
+
return spawnSync(command, args, {
|
|
186
|
+
cwd: ROOT,
|
|
187
|
+
encoding: 'utf8',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function summarizeProcess(result: SpawnSyncReturns<string>): string {
|
|
192
|
+
if (result.error) {
|
|
193
|
+
return result.error.message;
|
|
194
|
+
}
|
|
195
|
+
const combined = [result.stdout?.trim(), result.stderr?.trim()].filter(Boolean).join('\n');
|
|
196
|
+
const exitCode = result.status ?? 1;
|
|
197
|
+
if (!combined) {
|
|
198
|
+
return `command exited with code ${exitCode}`;
|
|
199
|
+
}
|
|
200
|
+
const lines = combined
|
|
201
|
+
.split(/\r?\n/)
|
|
202
|
+
.map(line => line.trim())
|
|
203
|
+
.filter(Boolean);
|
|
204
|
+
const tail = lines.slice(-3).join(' | ');
|
|
205
|
+
return `exit ${exitCode}: ${tail}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function autoSyncReverse(filePath: string): readonly [boolean, string] {
|
|
209
|
+
const buildResult = runNpm(['run', 'build:zova:admin']);
|
|
210
|
+
if (buildResult.status !== 0) {
|
|
211
|
+
return [false, `Auto-sync failed during \`npm run build:zova:admin\`: ${summarizeProcess(buildResult)}`];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const depsResult = runNpm(['run', 'deps:vona']);
|
|
215
|
+
if (depsResult.status !== 0) {
|
|
216
|
+
return [false, `Auto-sync failed during \`npm run deps:vona\`: ${summarizeProcess(depsResult)}`];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
markAutoSync(filePath);
|
|
220
|
+
return [true, 'Auto-sync ran `npm run build:zova:admin` and `npm run deps:vona` for this reverse-chain edit.'];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function buildMessages(filePath: string, result: AnalysisResult): string {
|
|
224
|
+
const messages = ["Contract-loop gate: this change may affect Cabloy's bidirectional contract loop."];
|
|
225
|
+
|
|
226
|
+
if (result.forwardReason) {
|
|
227
|
+
messages.push(
|
|
228
|
+
`Forward chain: ${result.forwardReason} If backend contract truth changed, verify the emitted OpenAPI/contract output and regenerate the frontend consumer path before considering the task done.`,
|
|
229
|
+
);
|
|
230
|
+
messages.push(
|
|
231
|
+
'After forward regeneration, keep frontend follow-up thin: prefer semantic model facades and reuse the existing resource-owner when the custom API still belongs to the same resource.',
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (result.reverseReason) {
|
|
236
|
+
messages.push(
|
|
237
|
+
`Reverse chain: ${result.reverseReason} If backend tooling or backend metadata will consume this handoff, refresh generated metadata when applicable, then run \`npm run build:zova:admin\` and \`npm run deps:vona\` for the Cabloy Basic Admin path.`,
|
|
238
|
+
);
|
|
239
|
+
if (isHighConfidenceReverseSource(filePath)) {
|
|
240
|
+
if (shouldSkipAutoSync(filePath)) {
|
|
241
|
+
messages.push('Auto-sync skipped because the same reverse-source edit was already synced recently in this repo.');
|
|
242
|
+
} else {
|
|
243
|
+
const [ok, detail] = autoSyncReverse(filePath);
|
|
244
|
+
messages.push(detail);
|
|
245
|
+
if (!ok) {
|
|
246
|
+
messages.push(
|
|
247
|
+
'Please review the failure before continuing. If generated artifacts already contain the expected changes but consumers still behave stale, suspect local dependency drift before making more source edits.',
|
|
248
|
+
);
|
|
249
|
+
return messages.join(' ');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
messages.push(
|
|
254
|
+
'Auto-sync did not run because this reverse-chain signal came from the consumer side rather than a high-confidence frontend source edit.',
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
messages.push(
|
|
258
|
+
'For Cabloy Start, apply the same reverse-chain logic but resolve the Start-specific flavor names and generated-output paths from the active Start repo before executing edition-specific steps.',
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return messages.join(' ');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function runClaudeHook(): number {
|
|
266
|
+
let payload: HookPayload;
|
|
267
|
+
try {
|
|
268
|
+
const raw = readFileSync(0, 'utf8');
|
|
269
|
+
payload = JSON.parse(raw) as HookPayload;
|
|
270
|
+
} catch {
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const filePath = normalizePath(payload.tool_input?.file_path);
|
|
275
|
+
if (!filePath || !isCodeFile(filePath)) return 0;
|
|
276
|
+
|
|
277
|
+
const content = readText(filePath);
|
|
278
|
+
if (content === null) return 0;
|
|
279
|
+
|
|
280
|
+
const result = analyze(filePath, content);
|
|
281
|
+
if (!hasSignal(result)) return 0;
|
|
282
|
+
|
|
283
|
+
const message = buildMessages(filePath, result);
|
|
284
|
+
console.log(
|
|
285
|
+
JSON.stringify({
|
|
286
|
+
hookSpecificOutput: {
|
|
287
|
+
hookEventName: 'PostToolUse',
|
|
288
|
+
additionalContext: message,
|
|
289
|
+
},
|
|
290
|
+
systemMessage: message,
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
process.exit(runClaudeHook());
|
|
@@ -36,6 +36,8 @@ Then classify the request:
|
|
|
36
36
|
|
|
37
37
|
Default to backend-first. Only escalate mentally to a broader fullstack workflow when the backend change obviously crosses the contract boundary.
|
|
38
38
|
|
|
39
|
+
If the user is still deciding a new business-domain boundary or suite/module naming, use the root `cabloy-domain-planning` skill before scaffolding.
|
|
40
|
+
|
|
39
41
|
If the task is really a broad cross-stack workflow, consider whether the root `cabloy-workflow` skill is the better primary router.
|
|
40
42
|
|
|
41
43
|
## Step 2: Start from Vona CLI and repo entrypoints
|
|
@@ -15,6 +15,7 @@ After generating or extending a backend thread, check which follow-up layers app
|
|
|
15
15
|
- OpenAPI metadata
|
|
16
16
|
- inferred DTO opportunities
|
|
17
17
|
- frontend contract impact
|
|
18
|
+
- `@Api.field(...)` / `$makeSchema(...)` ordering when an explicit zod/custom schema is present: put that schema last because `makeSchemaLikes(...)` applies arguments right-to-left and later helpers can otherwise be ignored
|
|
18
19
|
|
|
19
20
|
## Persistence follow-up
|
|
20
21
|
|
|
@@ -5,29 +5,44 @@ description: Use this skill whenever a Cabloy task crosses the Vona-to-Zova cont
|
|
|
5
5
|
|
|
6
6
|
# Cabloy Contract Loop
|
|
7
7
|
|
|
8
|
-
Use this skill when a backend contract change needs to be reflected in frontend consumers,
|
|
8
|
+
Use this skill when a backend contract change needs to be reflected in frontend consumers, when frontend-owned metadata or resources need to be reflected back into backend consumers, or when either side appears stale and you need to diagnose where drift actually lives.
|
|
9
|
+
|
|
10
|
+
Read the public [Contract Loop Playbook](../../../cabloy-docs/fullstack/contract-loop-playbook.md) for the canonical bidirectional model. This skill is the branching orchestration guide.
|
|
9
11
|
|
|
10
12
|
## Important recovery note for stale local file consumers
|
|
11
13
|
|
|
12
14
|
When generated `.zova-rest` output or other generated consumer artifacts already contain the expected new keys or types but Vona still behaves as if old consumer types are installed, treat that first as a local file-dependency installation problem rather than a source-editing problem.
|
|
13
15
|
|
|
16
|
+
This includes the reverse fullstack direction where newly added frontend resources such as custom renderers are later consumed by backend metadata.
|
|
17
|
+
|
|
14
18
|
In that situation:
|
|
15
19
|
|
|
16
20
|
1. run the normal sync or regeneration flow first
|
|
17
|
-
2. if
|
|
21
|
+
2. if Vona consumes newly added or changed Zova Admin render/action/metadata in Cabloy Basic, run `npm run build:zova:admin` from the repo root before anything else
|
|
22
|
+
3. otherwise, if the change only affects flavor-built REST/type output, rebuild the relevant Zova flavor output first
|
|
23
|
+
4. run `deps:vona`
|
|
24
|
+
5. if stale behavior remains, rebuild `vona/node_modules` and reinstall dependencies
|
|
18
25
|
|
|
19
26
|
Do not keep debugging source-level contract or renderer changes until the local file-package installation state is known to be healthy.
|
|
20
27
|
|
|
28
|
+
## Current safeguard behavior in this repo
|
|
29
|
+
|
|
30
|
+
- there is no contract-loop pre-commit gate in the current repo workflow
|
|
31
|
+
- the active safeguard lives in the Claude `PostToolUse` hook configured in `.claude/settings.json`
|
|
32
|
+
- for high-confidence reverse-chain source edits on the Zova side, the hook auto-runs `npm run build:zova:admin` and then `npm run deps:vona`
|
|
33
|
+
- forward-chain detections remain reminder-only, so backend contract changes still require deliberate regeneration and verification
|
|
34
|
+
- consumer-side reverse signals remain reminder-only, so do not assume every reverse-chain case auto-syncs itself
|
|
35
|
+
|
|
21
36
|
## Goals
|
|
22
37
|
|
|
23
38
|
1. detect whether the active repository is Cabloy Basic or Cabloy Start
|
|
24
39
|
2. classify whether the task truly crosses the backend/frontend contract boundary
|
|
25
|
-
3.
|
|
40
|
+
3. route the task into one of four modes: forward chain, reverse chain, consumer drift diagnosis, or local dependency drift recovery
|
|
26
41
|
4. keep the workflow contract-first instead of hand-patching generated frontend types or services
|
|
27
42
|
5. prefer CLI-first regeneration paths on both Vona and Zova sides
|
|
28
43
|
6. finish with end-to-end verification guidance that checks both contract production and consumption
|
|
29
44
|
|
|
30
|
-
## Step 1: Detect repo and
|
|
45
|
+
## Step 1: Detect repo, edition, and branch
|
|
31
46
|
|
|
32
47
|
Check the repository root for these marker files:
|
|
33
48
|
|
|
@@ -42,9 +57,11 @@ Interpretation:
|
|
|
42
57
|
|
|
43
58
|
Then classify whether the task is really a contract-loop task.
|
|
44
59
|
|
|
45
|
-
|
|
60
|
+
These four modes are shared across Cabloy Basic and Cabloy Start. Edition detection chooses the operational branch, but does not change the core contract-loop model.
|
|
46
61
|
|
|
47
|
-
|
|
62
|
+
Use this skill in four common entry modes.
|
|
63
|
+
|
|
64
|
+
### Mode A: forward chain
|
|
48
65
|
|
|
49
66
|
The user already changed or plans to change backend contract surfaces such as:
|
|
50
67
|
|
|
@@ -55,7 +72,18 @@ The user already changed or plans to change backend contract surfaces such as:
|
|
|
55
72
|
- OpenAPI metadata
|
|
56
73
|
- inferred DTO or ORM DTO output that affects API consumers
|
|
57
74
|
|
|
58
|
-
### Mode B: reverse
|
|
75
|
+
### Mode B: reverse chain
|
|
76
|
+
|
|
77
|
+
The user changed or plans to change frontend-owned resources or metadata that backend-side tooling or metadata will later consume, such as:
|
|
78
|
+
|
|
79
|
+
- routes
|
|
80
|
+
- components
|
|
81
|
+
- icons
|
|
82
|
+
- custom form-field resources
|
|
83
|
+
- custom table-cell resources
|
|
84
|
+
- generated frontend metadata that backend `ZovaRender.*(...)` references depend on
|
|
85
|
+
|
|
86
|
+
### Mode C: consumer drift diagnosis
|
|
59
87
|
|
|
60
88
|
The user reports symptoms on the frontend side such as:
|
|
61
89
|
|
|
@@ -64,7 +92,11 @@ The user reports symptoms on the frontend side such as:
|
|
|
64
92
|
- API/model consumers no longer matching backend reality
|
|
65
93
|
- hand-patched frontend types that seem to drift from backend truth
|
|
66
94
|
|
|
67
|
-
In this mode, first diagnose whether the
|
|
95
|
+
In this mode, first diagnose whether the visible stale behavior comes from skipped regeneration, a wrong source-of-truth edit, or a stale generated consumer.
|
|
96
|
+
|
|
97
|
+
### Mode D: local dependency drift recovery
|
|
98
|
+
|
|
99
|
+
Use this mode when generated artifacts already contain the expected keys, types, or resources, but installed local file dependencies still behave stale after the normal sync flow.
|
|
68
100
|
|
|
69
101
|
If the task is only backend scaffolding or only frontend scaffolding, the more specialized scaffold skills may be the better primary choice.
|
|
70
102
|
|
|
@@ -86,9 +118,9 @@ For deeper reference material, read:
|
|
|
86
118
|
|
|
87
119
|
## Step 3: Identify the contract source of truth deliberately
|
|
88
120
|
|
|
89
|
-
In Cabloy, the backend is often the source of truth for the contract. Treat that as the default unless the codebase clearly shows a
|
|
121
|
+
In Cabloy, the backend is often the source of truth for the contract. Treat that as the default unless the codebase clearly shows a frontend-owned artifact that the reverse chain should hand back into backend consumers.
|
|
90
122
|
|
|
91
|
-
### If this is
|
|
123
|
+
### If this is the forward chain
|
|
92
124
|
|
|
93
125
|
Start with the backend side and update the contract deliberately.
|
|
94
126
|
|
|
@@ -105,16 +137,37 @@ The key rule is:
|
|
|
105
137
|
|
|
106
138
|
- do **not** patch frontend consumers first if the backend contract is the real source of truth
|
|
107
139
|
|
|
108
|
-
### If this is reverse
|
|
140
|
+
### If this is the reverse chain
|
|
109
141
|
|
|
110
|
-
|
|
142
|
+
Start with the frontend-owned resource or metadata that backend consumers later depend on.
|
|
143
|
+
|
|
144
|
+
Typical frontend layers to inspect or change include:
|
|
145
|
+
|
|
146
|
+
- routes
|
|
147
|
+
- components
|
|
148
|
+
- icons
|
|
149
|
+
- custom form-field resources
|
|
150
|
+
- custom table-cell resources
|
|
151
|
+
- generated metadata that backend `ZovaRender.*(...)` references depend on
|
|
152
|
+
|
|
153
|
+
The key rule is:
|
|
154
|
+
|
|
155
|
+
- do **not** treat this as frontend-only cleanup if backend consumers depend on the generated handoff
|
|
156
|
+
|
|
157
|
+
### If this is consumer drift diagnosis
|
|
158
|
+
|
|
159
|
+
Do not assume the visible stale behavior identifies the wrong layer automatically.
|
|
111
160
|
|
|
112
161
|
Instead:
|
|
113
162
|
|
|
114
|
-
1. inspect what
|
|
163
|
+
1. inspect what artifact looks stale
|
|
115
164
|
2. identify whether that artifact is generated, schema-driven, or hand-authored
|
|
116
|
-
3. inspect the
|
|
117
|
-
4. only then decide whether the fix is regeneration,
|
|
165
|
+
3. inspect the source layer that should feed it
|
|
166
|
+
4. only then decide whether the fix is regeneration, source correction, consumer alignment, or a genuine bug
|
|
167
|
+
|
|
168
|
+
### If this is local dependency drift recovery
|
|
169
|
+
|
|
170
|
+
Only enter this branch after the source layer and generated handoff are already known to be correct.
|
|
118
171
|
|
|
119
172
|
## Step 4: Verify backend contract output before touching frontend consumers
|
|
120
173
|
|
|
@@ -126,6 +179,7 @@ That may include:
|
|
|
126
179
|
- confirming DTO and validation alignment
|
|
127
180
|
- checking Swagger/OpenAPI output
|
|
128
181
|
- confirming that the changed endpoint or schema now reflects the intended contract
|
|
182
|
+
- if local OpenAPI generation depends on a running Swagger source, starting the backend service first — in Cabloy Basic, `npm run dev` is the normal path and exposes `http://localhost:7102/swagger/json?version=V31`
|
|
129
183
|
|
|
130
184
|
If the backend contract output is wrong, frontend regeneration will only spread the mistake.
|
|
131
185
|
|
|
@@ -142,6 +196,11 @@ Typical Zova commands include:
|
|
|
142
196
|
- `npm run zova :openapi:config ...`
|
|
143
197
|
- `npm run zova :openapi:generate ...`
|
|
144
198
|
|
|
199
|
+
Preflight reminder:
|
|
200
|
+
|
|
201
|
+
- if `:openapi:generate` reads from a local Swagger endpoint, do not assume the generator itself is broken when fetch fails
|
|
202
|
+
- first start the backend service, typically with `npm run dev`, and confirm `http://localhost:7102/swagger/json?version=V31` is reachable
|
|
203
|
+
|
|
145
204
|
When the target is a module-local SDK, constrain `openapi.config.ts` with `operations.match` unless the module intentionally owns a broad API surface. This prevents unrelated APIs from being generated into the module.
|
|
146
205
|
|
|
147
206
|
### Path B: REST/type generation by flavor
|
|
@@ -153,6 +212,15 @@ Typical examples in Cabloy Basic include:
|
|
|
153
212
|
- `cd zova && npm run build:rest:cabloyBasicAdmin`
|
|
154
213
|
- `cd zova && npm run build:rest:cabloyBasicWeb`
|
|
155
214
|
|
|
215
|
+
Important Cabloy Basic reverse-sync rule:
|
|
216
|
+
|
|
217
|
+
- if Vona consumes newly added or changed Zova Admin render/action/metadata, do **not** stop at `build:rest:cabloyBasicAdmin`
|
|
218
|
+
- run `npm run build:zova:admin` from the repo root instead, then run `npm run deps:vona`
|
|
219
|
+
- treat this as a JS-bundle-plus-rest-output handoff, not a rest-types-only refresh
|
|
220
|
+
- the current repo safeguard may auto-run those two commands for high-confidence Zova reverse-source edits, but only as a convenience layer on top of the contract-loop model
|
|
221
|
+
- if the change was consumer-side, low-confidence, cross-edition, or happened outside the Claude hook path, run the reverse sync flow deliberately yourself
|
|
222
|
+
- prefer visible proof under `zova/src/**/.metadata/**` when it is available; if the effective handoff only appears in `.zova-rest`, treat the safeguard as conservative reminder/auto-sync assistance rather than strict proof
|
|
223
|
+
|
|
156
224
|
For Cabloy Start, verify the exact Start-specific flavor names, paths, SSR site baselines, and project assets in the licensed Start repo.
|
|
157
225
|
|
|
158
226
|
### Path C: Downstream frontend alignment
|
|
@@ -164,7 +232,12 @@ After generation, inspect whether the frontend still needs follow-up in:
|
|
|
164
232
|
- schema-driven UI
|
|
165
233
|
- page or component assumptions
|
|
166
234
|
|
|
167
|
-
|
|
235
|
+
Keep frontend follow-up thin:
|
|
236
|
+
|
|
237
|
+
- use thin semantic model facades over generated consumers instead of re-declaring the contract
|
|
238
|
+
- if a custom endpoint still belongs to an existing resource, prefer one resource-state owner instead of letting a module-local model create a second cache tree
|
|
239
|
+
|
|
240
|
+
Reuse the resource-owned custom state pattern in `references/resource-custom-state-pattern.md`.
|
|
168
241
|
|
|
169
242
|
## Step 6: Keep edition-aware differences explicit
|
|
170
243
|
|
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference when a task crosses the backend/frontend contract boundary.
|
|
4
4
|
|
|
5
|
+
This map is symmetric across Cabloy Basic and Cabloy Start. Detect the active edition to choose commands and output paths, but keep the same four-way diagnosis model:
|
|
6
|
+
|
|
7
|
+
- forward chain
|
|
8
|
+
- reverse chain
|
|
9
|
+
- consumer drift
|
|
10
|
+
- local dependency drift
|
|
11
|
+
|
|
5
12
|
## Typical triggers
|
|
6
13
|
|
|
7
|
-
###
|
|
14
|
+
### Forward chain
|
|
8
15
|
|
|
9
16
|
Common examples:
|
|
10
17
|
|
|
@@ -19,18 +26,45 @@ Likely next step:
|
|
|
19
26
|
- verify backend OpenAPI output
|
|
20
27
|
- regenerate the frontend consumer path
|
|
21
28
|
|
|
22
|
-
###
|
|
29
|
+
### Reverse chain
|
|
30
|
+
|
|
31
|
+
Common examples:
|
|
32
|
+
|
|
33
|
+
- backend metadata now references a new frontend table cell or form field
|
|
34
|
+
- routes, components, or icons changed and backend-side tooling depends on them
|
|
35
|
+
- frontend-generated metadata needs to be consumed back into Vona
|
|
36
|
+
|
|
37
|
+
Likely next step:
|
|
38
|
+
|
|
39
|
+
- regenerate frontend metadata or build output
|
|
40
|
+
- run the correct flavor build for the active edition
|
|
41
|
+
- run `deps:vona`
|
|
42
|
+
|
|
43
|
+
### Consumer drift
|
|
23
44
|
|
|
24
45
|
Common examples:
|
|
25
46
|
|
|
26
|
-
- generated SDK no longer matches
|
|
47
|
+
- generated SDK no longer matches visible frontend behavior
|
|
27
48
|
- schema-driven UI expects old shape
|
|
28
49
|
- model or API service types are stale
|
|
29
50
|
|
|
30
51
|
Likely next step:
|
|
31
52
|
|
|
32
|
-
- confirm whether
|
|
33
|
-
- regenerate instead of hand-patching
|
|
53
|
+
- confirm whether source truth or generated output really changed
|
|
54
|
+
- regenerate instead of hand-patching when the generated layer is the stale one
|
|
55
|
+
|
|
56
|
+
### Local dependency drift
|
|
57
|
+
|
|
58
|
+
Common examples:
|
|
59
|
+
|
|
60
|
+
- generated artifacts already contain the expected change
|
|
61
|
+
- normal sync already ran
|
|
62
|
+
- installed local file consumers still behave stale
|
|
63
|
+
|
|
64
|
+
Likely next step:
|
|
65
|
+
|
|
66
|
+
- stop editing source files
|
|
67
|
+
- repair install state only after proving the earlier stages are healthy
|
|
34
68
|
|
|
35
69
|
## Module-local OpenAPI generation boundary
|
|
36
70
|
|
|
@@ -58,15 +92,69 @@ Practical check after generation:
|
|
|
58
92
|
- confirm the generated API files only contain the intended resource operations
|
|
59
93
|
- confirm the module metadata and exports were not polluted by unrelated APIs
|
|
60
94
|
|
|
61
|
-
##
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
## Forward chain artifact map
|
|
96
|
+
|
|
97
|
+
1. backend contract source
|
|
98
|
+
- controllers
|
|
99
|
+
- DTOs
|
|
100
|
+
- entities
|
|
101
|
+
- validation rules
|
|
102
|
+
- OpenAPI metadata
|
|
103
|
+
2. emitted proof surface
|
|
104
|
+
- Swagger/OpenAPI output
|
|
105
|
+
3. generated handoff
|
|
106
|
+
- generated SDK
|
|
107
|
+
- schema-aware helpers
|
|
108
|
+
- flavor-built REST output when needed
|
|
109
|
+
4. consumer layers
|
|
110
|
+
- frontend API files
|
|
111
|
+
- thin model facades
|
|
112
|
+
- schema-driven UI
|
|
113
|
+
- row and page actions
|
|
114
|
+
|
|
115
|
+
## Reverse chain artifact map
|
|
116
|
+
|
|
117
|
+
1. frontend contract source
|
|
118
|
+
- routes
|
|
119
|
+
- components
|
|
120
|
+
- icons
|
|
121
|
+
- custom table cells
|
|
122
|
+
- custom form-field resources
|
|
123
|
+
- module metadata
|
|
124
|
+
2. generated handoff
|
|
125
|
+
- metadata output
|
|
126
|
+
- flavor build output
|
|
127
|
+
3. sync surface
|
|
128
|
+
- `deps:vona`
|
|
129
|
+
4. consumer layers
|
|
130
|
+
- backend `ZovaRender.*(...)` references
|
|
131
|
+
- backend tooling and type hints
|
|
132
|
+
- SSR or integration paths that depend on refreshed frontend output
|
|
133
|
+
|
|
134
|
+
## Drift diagnosis matrix
|
|
135
|
+
|
|
136
|
+
### Source wrong
|
|
137
|
+
|
|
138
|
+
- wrong layer was edited
|
|
139
|
+
- emitted or generated output is therefore wrong
|
|
140
|
+
- fix the contract source first
|
|
141
|
+
|
|
142
|
+
### Generated output wrong
|
|
143
|
+
|
|
144
|
+
- source is correct, but generation did not run or ran on the wrong boundary
|
|
145
|
+
- regenerate rather than hand-patch consumers
|
|
146
|
+
|
|
147
|
+
### Consumer stale
|
|
148
|
+
|
|
149
|
+
- generated output is correct, but the next consumer layer is still reading old expectations
|
|
150
|
+
- inspect the consumer path before changing source again
|
|
151
|
+
|
|
152
|
+
### Install stale
|
|
153
|
+
|
|
154
|
+
- generated output is correct
|
|
155
|
+
- normal sync already ran
|
|
156
|
+
- local file dependencies still behave stale
|
|
157
|
+
- repair install state only after proving the earlier stages are healthy
|
|
70
158
|
|
|
71
159
|
## Anti-pattern
|
|
72
160
|
|