@rawsql-ts/ztd-cli 0.16.0 → 0.19.0
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/README.md +532 -353
- package/package.json +35 -17
- package/templates/.editorconfig +16 -16
- package/templates/.prettierignore +2 -2
- package/templates/.prettierrc +24 -24
- package/templates/AGENTS.md +30 -325
- package/templates/CONTEXT.md +11 -0
- package/templates/CONTEXT.webapi.md +11 -0
- package/templates/DESIGN.md +17 -0
- package/templates/DEV_NOTES.md +14 -0
- package/templates/PROMPT_DOGFOOD.webapi.md +49 -0
- package/templates/README.md +46 -217
- package/templates/README.webapi.md +38 -0
- package/templates/scripts/local-source-guard.mjs +189 -0
- package/templates/src/AGENTS.md +26 -0
- package/templates/src/application/AGENTS.md +15 -0
- package/templates/src/application/README.md +6 -0
- package/templates/src/catalog/AGENTS.md +28 -0
- package/templates/src/catalog/runtime/AGENTS.md +28 -0
- package/templates/src/catalog/runtime/_coercions.local-source.ts +30 -0
- package/templates/src/catalog/runtime/_coercions.ts +30 -0
- package/templates/src/catalog/runtime/_smoke.runtime.ts +21 -0
- package/templates/src/catalog/specs/AGENTS.md +41 -0
- package/templates/src/catalog/specs/_smoke.spec.arktype.ts +21 -0
- package/templates/src/catalog/specs/_smoke.spec.zod.ts +20 -0
- package/templates/src/db/sql-client-adapters.ts +32 -0
- package/templates/src/db/sql-client.ts +24 -24
- package/templates/src/domain/AGENTS.md +15 -0
- package/templates/src/domain/README.md +6 -0
- package/templates/src/infrastructure/AGENTS.md +14 -0
- package/templates/src/infrastructure/README.md +6 -0
- package/templates/src/infrastructure/db/AGENTS.md +14 -0
- package/templates/src/infrastructure/db/sql-client-adapters.ts +34 -0
- package/templates/src/infrastructure/db/sql-client.ts +24 -0
- package/templates/src/infrastructure/persistence/AGENTS.md +18 -0
- package/templates/src/infrastructure/persistence/README.md +8 -0
- package/templates/src/infrastructure/persistence/repositories/AGENTS.md +17 -0
- package/templates/src/infrastructure/persistence/repositories/tables/AGENTS.md +20 -0
- package/templates/src/infrastructure/persistence/repositories/tables/README.md +5 -0
- package/templates/src/infrastructure/persistence/repositories/views/AGENTS.md +16 -0
- package/templates/src/infrastructure/persistence/repositories/views/README.md +5 -0
- package/templates/src/infrastructure/telemetry/AGENTS.md +14 -0
- package/templates/src/infrastructure/telemetry/consoleRepositoryTelemetry.ts +66 -0
- package/templates/src/infrastructure/telemetry/repositoryTelemetry.ts +26 -0
- package/templates/src/infrastructure/telemetry/types.ts +48 -0
- package/templates/src/jobs/AGENTS.md +25 -0
- package/templates/src/jobs/README.md +3 -0
- package/templates/src/local/sql-contract.ts +1 -0
- package/templates/src/presentation/AGENTS.md +15 -0
- package/templates/src/presentation/http/AGENTS.md +15 -0
- package/templates/src/presentation/http/README.md +6 -0
- package/templates/src/repositories/AGENTS.md +30 -0
- package/templates/src/repositories/tables/AGENTS.md +29 -0
- package/templates/src/repositories/tables/README.md +5 -0
- package/templates/src/repositories/views/AGENTS.md +25 -0
- package/templates/src/repositories/views/README.md +5 -0
- package/templates/src/sql/AGENTS.md +30 -0
- package/templates/src/sql/README.md +6 -0
- package/templates/tests/AGENTS.md +29 -169
- package/templates/tests/generated/AGENTS.md +23 -0
- package/templates/tests/smoke.test.ts +25 -0
- package/templates/tests/smoke.validation.test.ts +34 -0
- package/templates/tests/support/AGENTS.md +24 -0
- package/templates/tests/support/global-setup.ts +15 -30
- package/templates/tests/support/testkit-client.ts +14 -742
- package/templates/tests/support/testkit-client.webapi.ts +14 -0
- package/templates/tests/ztd-layout.generated.ts +6 -6
- package/templates/tsconfig.json +15 -8
- package/templates/vitest.config.ts +13 -13
- package/templates/ztd/AGENTS.md +23 -74
- package/templates/ztd/README.md +6 -15
- package/templates/ztd/ddl/AGENTS.md +26 -0
- package/templates/ztd/ddl/demo.sql +74 -0
- package/LICENSE +0 -21
- package/dist/commands/ddl.d.ts +0 -7
- package/dist/commands/ddl.js +0 -118
- package/dist/commands/ddl.js.map +0 -1
- package/dist/commands/diff.d.ts +0 -10
- package/dist/commands/diff.js +0 -38
- package/dist/commands/diff.js.map +0 -1
- package/dist/commands/genEntities.d.ts +0 -6
- package/dist/commands/genEntities.js +0 -50
- package/dist/commands/genEntities.js.map +0 -1
- package/dist/commands/init.d.ts +0 -66
- package/dist/commands/init.js +0 -838
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/lint.d.ts +0 -59
- package/dist/commands/lint.js +0 -338
- package/dist/commands/lint.js.map +0 -1
- package/dist/commands/options.d.ts +0 -9
- package/dist/commands/options.js +0 -48
- package/dist/commands/options.js.map +0 -1
- package/dist/commands/pull.d.ts +0 -10
- package/dist/commands/pull.js +0 -105
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/ztdConfig.d.ts +0 -23
- package/dist/commands/ztdConfig.js +0 -202
- package/dist/commands/ztdConfig.js.map +0 -1
- package/dist/commands/ztdConfigCommand.d.ts +0 -5
- package/dist/commands/ztdConfigCommand.js +0 -157
- package/dist/commands/ztdConfigCommand.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -22
- package/dist/index.js.map +0 -1
- package/dist/utils/agents.d.ts +0 -1
- package/dist/utils/agents.js +0 -48
- package/dist/utils/agents.js.map +0 -1
- package/dist/utils/collectSqlFiles.d.ts +0 -9
- package/dist/utils/collectSqlFiles.js +0 -58
- package/dist/utils/collectSqlFiles.js.map +0 -1
- package/dist/utils/connectionSummary.d.ts +0 -3
- package/dist/utils/connectionSummary.js +0 -29
- package/dist/utils/connectionSummary.js.map +0 -1
- package/dist/utils/dbConnection.d.ts +0 -29
- package/dist/utils/dbConnection.js +0 -210
- package/dist/utils/dbConnection.js.map +0 -1
- package/dist/utils/fs.d.ts +0 -1
- package/dist/utils/fs.js +0 -12
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/normalizePulledSchema.d.ts +0 -12
- package/dist/utils/normalizePulledSchema.js +0 -213
- package/dist/utils/normalizePulledSchema.js.map +0 -1
- package/dist/utils/pgDump.d.ts +0 -11
- package/dist/utils/pgDump.js +0 -55
- package/dist/utils/pgDump.js.map +0 -1
- package/dist/utils/sqlLintHelpers.d.ts +0 -18
- package/dist/utils/sqlLintHelpers.js +0 -270
- package/dist/utils/sqlLintHelpers.js.map +0 -1
- package/dist/utils/typeMapper.d.ts +0 -4
- package/dist/utils/typeMapper.js +0 -76
- package/dist/utils/typeMapper.js.map +0 -1
- package/dist/utils/ztdProjectConfig.d.ts +0 -40
- package/dist/utils/ztdProjectConfig.js +0 -167
- package/dist/utils/ztdProjectConfig.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.d.ts +0 -38
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js +0 -117
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.d.ts +0 -4
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js +0 -71
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/index.d.ts +0 -5
- package/templates/dist/drivers/pg-testkit/src/index.js +0 -11
- package/templates/dist/drivers/pg-testkit/src/index.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.d.ts +0 -3
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js +0 -79
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/types.d.ts +0 -69
- package/templates/dist/drivers/pg-testkit/src/types.js +0 -3
- package/templates/dist/drivers/pg-testkit/src/types.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.d.ts +0 -15
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js +0 -34
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js.map +0 -1
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.d.ts +0 -12
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js +0 -53
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js.map +0 -1
- package/templates/dist/mapper-core/src/index.d.ts +0 -160
- package/templates/dist/mapper-core/src/index.js +0 -637
- package/templates/dist/mapper-core/src/index.js.map +0 -1
- package/templates/dist/testkit-core/src/errors/index.d.ts +0 -49
- package/templates/dist/testkit-core/src/errors/index.js +0 -111
- package/templates/dist/testkit-core/src/errors/index.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.d.ts +0 -5
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js +0 -29
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.d.ts +0 -37
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js +0 -182
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.d.ts +0 -20
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js +0 -121
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.d.ts +0 -51
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.js +0 -199
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.d.ts +0 -10
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js +0 -28
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.d.ts +0 -18
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js +0 -80
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/ddlLint.d.ts +0 -59
- package/templates/dist/testkit-core/src/fixtures/ddlLint.js +0 -489
- package/templates/dist/testkit-core/src/fixtures/ddlLint.js.map +0 -1
- package/templates/dist/testkit-core/src/fixtures/naming.d.ts +0 -1
- package/templates/dist/testkit-core/src/fixtures/naming.js +0 -6
- package/templates/dist/testkit-core/src/fixtures/naming.js.map +0 -1
- package/templates/dist/testkit-core/src/index.d.ts +0 -17
- package/templates/dist/testkit-core/src/index.js +0 -47
- package/templates/dist/testkit-core/src/index.js.map +0 -1
- package/templates/dist/testkit-core/src/logger/NoopLogger.d.ts +0 -8
- package/templates/dist/testkit-core/src/logger/NoopLogger.js +0 -16
- package/templates/dist/testkit-core/src/logger/NoopLogger.js.map +0 -1
- package/templates/dist/testkit-core/src/provider/TestkitProvider.d.ts +0 -57
- package/templates/dist/testkit-core/src/provider/TestkitProvider.js +0 -149
- package/templates/dist/testkit-core/src/provider/TestkitProvider.js.map +0 -1
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.d.ts +0 -43
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js +0 -473
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js.map +0 -1
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.d.ts +0 -9
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js +0 -38
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js.map +0 -1
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.d.ts +0 -42
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js +0 -298
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js.map +0 -1
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.d.ts +0 -12
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js +0 -63
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js.map +0 -1
- package/templates/dist/testkit-core/src/types/index.d.ts +0 -69
- package/templates/dist/testkit-core/src/types/index.js +0 -3
- package/templates/dist/testkit-core/src/types/index.js.map +0 -1
- package/templates/dist/testkit-core/src/utils/queryHelpers.d.ts +0 -28
- package/templates/dist/testkit-core/src/utils/queryHelpers.js +0 -81
- package/templates/dist/testkit-core/src/utils/queryHelpers.js.map +0 -1
- package/templates/dist/writer-core/src/index.d.ts +0 -34
- package/templates/dist/writer-core/src/index.js +0 -115
- package/templates/dist/writer-core/src/index.js.map +0 -1
- package/templates/dist/ztd-cli/templates/src/db/sql-client.d.ts +0 -20
- package/templates/dist/ztd-cli/templates/src/db/sql-client.js +0 -3
- package/templates/dist/ztd-cli/templates/src/db/sql-client.js.map +0 -1
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.d.ts +0 -36
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js +0 -85
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.d.ts +0 -20
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js +0 -33
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.d.ts +0 -10
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.js +0 -29
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.d.ts +0 -66
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js +0 -552
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.d.ts +0 -1
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js +0 -82
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.d.ts +0 -1
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js +0 -29
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js.map +0 -1
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.d.ts +0 -7
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js +0 -10
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js.map +0 -1
- package/templates/src/repositories/user-accounts.ts +0 -179
- package/templates/tests/user-profiles.test.ts +0 -161
- package/templates/tests/writer-constraints.test.ts +0 -32
package/templates/README.md
CHANGED
|
@@ -1,217 +1,46 @@
|
|
|
1
|
-
# Zero Table Dependency Project
|
|
2
|
-
|
|
3
|
-
This project
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
let sharedClient: SqlClient | undefined;
|
|
48
|
-
|
|
49
|
-
export function getSqlClient(): SqlClient {
|
|
50
|
-
if (!sharedClient) {
|
|
51
|
-
// Create the client once using your chosen driver (pg, mysql, etc.).
|
|
52
|
-
sharedClient = createSqlClientOnce();
|
|
53
|
-
}
|
|
54
|
-
return sharedClient;
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
# Mapper + writer sample
|
|
61
|
-
|
|
62
|
-
- This scaffold already exposes `src/repositories/user-accounts.ts`, which maps `public.user_account` rows together with optional `public.user_profile` data through `@rawsql-ts/sql-contract/mapper` and emits insert/update/remove helpers via `@rawsql-ts/sql-contract/writer`.
|
|
63
|
-
- The SQL used here is defined in `src/repositories/user-accounts.ts`; the template tests exercise that implementation and `ztd/ddl` is the authoritative source for every column and constraint.
|
|
64
|
-
- Two template tests demonstrate how to run the stitch:
|
|
65
|
-
- `tests/user-profiles.test.ts` seeds fixtures, executes the query through the mapper, and verifies the DTO shape.
|
|
66
|
-
- `tests/writer-constraints.test.ts` reads `userAccountWriterColumnSets` plus `tests/generated/ztd-row-map.generated.ts` so writer callers stay within the approved column set when referencing `public.user_account`.
|
|
67
|
-
- Regenerate `tests/generated/ztd-row-map.generated.ts` (`npx ztd ztd-config`) before running the example tests so the row map reflects any schema changes.
|
|
68
|
-
- The example tests require a real PostgreSQL connection via `DATABASE_URL`; they automatically skip when the variable is missing so local tooling stays fast.
|
|
69
|
-
|
|
70
|
-
# Principles
|
|
71
|
-
|
|
72
|
-
### 1. Humans own the *definitions*
|
|
73
|
-
- DDL (physical schema)
|
|
74
|
-
Only `ztd/ddl` is part of the template contract; other subdirectories should not be assumed.
|
|
75
|
-
|
|
76
|
-
### 2. AI owns the *implementation*
|
|
77
|
-
- Repository SQL generation
|
|
78
|
-
- Test fixture updates
|
|
79
|
-
- Intermediate TypeScript structures
|
|
80
|
-
- SQL rewriting, parameter binding, shape resolution
|
|
81
|
-
|
|
82
|
-
### 3. ZTD ensures these stay in sync
|
|
83
|
-
ZTD acts as the consistency layer ensuring:
|
|
84
|
-
- DDL → SQL shape consistency
|
|
85
|
-
- Do not rely on other directories unless the project explicitly adds them.
|
|
86
|
-
|
|
87
|
-
If any part diverges, ZTD tests fail deterministically.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
# Workflow Overview
|
|
92
|
-
|
|
93
|
-
Different tasks start from different entry points. Choose the workflow that matches what you want to change.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
# Workflow A — Starting From *DDL Changes*
|
|
98
|
-
(Adding tables/columns, changing constraints)
|
|
99
|
-
|
|
100
|
-
1. Edit files under `ztd/ddl/`.
|
|
101
|
-
2. Run:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
npx ztd ztd-config
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
This regenerates `tests/generated/ztd-row-map.generated.ts` from the new schema.
|
|
108
|
-
|
|
109
|
-
3. Update repository SQL so it matches the new schema.
|
|
110
|
-
4. Update fixtures if shapes changed.
|
|
111
|
-
5. Run tests. Any schema mismatch will fail fast.
|
|
112
|
-
|
|
113
|
-
**Flow:**
|
|
114
|
-
**DDL -> repository SQL -> fixtures/tests -> application**
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
# Workflow B — Starting From *Repository Interface Changes*
|
|
119
|
-
(Adding a method, changing return types, etc.)
|
|
120
|
-
|
|
121
|
-
1. Modify the repository interface or class in `/src`.
|
|
122
|
-
2. Allow AI to generate the SQL needed to satisfy the interface.
|
|
123
|
-
3. If the query contradicts DDL, reconcile the authoritative definition before continuing.
|
|
124
|
-
4. Run ZTD tests to confirm logic is consistent.
|
|
125
|
-
5. Regenerate ZTD config if result shapes changed.
|
|
126
|
-
|
|
127
|
-
**Flow:**
|
|
128
|
-
**repository interface -> SQL -> tests**
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
# Workflow C — Starting From Repository SQL Logic Changes
|
|
133
|
-
(Fixing a bug, optimizing logic, rewriting a query)
|
|
134
|
-
|
|
135
|
-
1. Edit SQL inside the repository.
|
|
136
|
-
2. Run ZTD tests.
|
|
137
|
-
3. If the intended behavior changes, update the DDL before adjusting dependent logic and keep documentation aligned with the confirmed schema.
|
|
138
|
-
4. Update fixtures as necessary.
|
|
139
|
-
5. If SQL result shape changed, run:
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
npx ztd ztd-config
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**Flow:**
|
|
146
|
-
**SQL -> fixtures/tests**
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
# Combined Real‑World Flow Examples
|
|
151
|
-
|
|
152
|
-
- **Add a new contract status**
|
|
153
|
-
DDL -> SQL -> config -> tests
|
|
154
|
-
|
|
155
|
-
- **Add a new table**
|
|
156
|
-
DDL -> config -> SQL -> fixtures -> tests
|
|
157
|
-
|
|
158
|
-
- **Fix business logic**
|
|
159
|
-
SQL -> tests
|
|
160
|
-
|
|
161
|
-
ZTD ensures all changes converge into a consistent, validated workflow.
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
# Human Responsibilities
|
|
165
|
-
|
|
166
|
-
- Humans maintain:
|
|
167
|
-
- Physical schema (`ddl`)
|
|
168
|
-
- High‑level repository interfaces
|
|
169
|
-
- Acceptance of AI-generated changes
|
|
170
|
-
|
|
171
|
-
Humans decide “what is correct.”
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
# AI Responsibilities
|
|
176
|
-
|
|
177
|
-
AI must:
|
|
178
|
-
|
|
179
|
-
- Use DDL as the **physical shape constraint** and primary source of truth.
|
|
180
|
-
- Do not assume any additional `ztd` directories exist unless a human explicitly creates them.
|
|
181
|
-
- Generate repository SQL consistent with DDL and the documented behavior.
|
|
182
|
-
- Regenerate fixtures and tests as instructed.
|
|
183
|
-
- Never modify `ztd/AGENTS.md` or `ztd/README.md` unless explicitly asked.
|
|
184
|
-
|
|
185
|
-
AI decides “how to implement” within those constraints.
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
# ZTD CLI Responsibilities
|
|
190
|
-
|
|
191
|
-
ZTD CLI:
|
|
192
|
-
|
|
193
|
-
- Parses DDL files to build accurate table/column shapes
|
|
194
|
-
- Rewrites SQL with fixture-based CTE shadowing (via testkit adapters)
|
|
195
|
-
- Generates `ztd-row-map.generated.ts`
|
|
196
|
-
- Produces deterministic, parallelizable tests
|
|
197
|
-
|
|
198
|
-
ZTD is the verification engine guaranteeing correctness.
|
|
199
|
-
|
|
200
|
-
## Traditional execution mode
|
|
201
|
-
|
|
202
|
-
- Set `ZTD_EXECUTION_MODE=traditional` or pass `{ mode: 'traditional', traditional: { isolation: 'schema', cleanup: 'drop_schema' } }` when you need to run the tests against a real Postgres schema (locking, isolation, constraints). The helper still applies the DDL inside `ztd/ddl/`, loads the fixture rows into the schema, optionally executes `setupSql`, and carries out the chosen cleanup strategy (`drop_schema`, `custom_sql`, or `none`).
|
|
203
|
-
- Use `isolation: 'none'` if you need to target a schema that is already defined or if your SQL embeds schema qualifiers explicitly.
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
# Summary
|
|
208
|
-
|
|
209
|
-
ZTD enables a workflow where **humans define meaning**, **AI writes implementation**, and **tests guarantee correctness**.
|
|
210
|
-
|
|
211
|
-
The project layout and workflows above ensure long-term maintainability, clarity, and full reproducibility of SQL logic independent of physical database state.
|
|
212
|
-
|
|
213
|
-
## Recommended local verification
|
|
214
|
-
|
|
215
|
-
- `npx ztd ztd-config` (Recommended)
|
|
216
|
-
- `pnpm -C packages/ztd-cli test` (Recommended)
|
|
217
|
-
- `templates/tests/user-profiles.test.ts` runs only when `DATABASE_URL` is configured; otherwise it skips automatically.
|
|
1
|
+
# Zero Table Dependency Project
|
|
2
|
+
|
|
3
|
+
This project uses Zero Table Dependency (ZTD) to keep SQL, DDL, and tests aligned.
|
|
4
|
+
|
|
5
|
+
Conceptual model:
|
|
6
|
+
- `ztd-cli` implicitly uses only `ZTD_TEST_DATABASE_URL`.
|
|
7
|
+
- `DATABASE_URL` and other runtime or deployment database settings are outside the ownership of `ztd-cli`.
|
|
8
|
+
- Any non-ZTD database target must be passed explicitly via `--url` or `--db-*`.
|
|
9
|
+
- `ztd-cli` may generate migration SQL artifacts, but it does not apply them.
|
|
10
|
+
|
|
11
|
+
Quick boundary table:
|
|
12
|
+
- `ZTD_TEST_DATABASE_URL`: owned by `ztd-cli` for ZTD tests and verification
|
|
13
|
+
- `DATABASE_URL`: runtime or deployment concern, not read automatically by `ztd-cli`
|
|
14
|
+
- `--url` / complete `--db-*`: explicit target inspection only
|
|
15
|
+
|
|
16
|
+
Key folders:
|
|
17
|
+
- ztd/ddl: schema files (source of truth)
|
|
18
|
+
- src: application SQL and repositories
|
|
19
|
+
- tests: ZTD tests and support
|
|
20
|
+
|
|
21
|
+
Next steps:
|
|
22
|
+
1. Update `ztd/ddl/<schema>.sql` if needed.
|
|
23
|
+
2. Run `pnpm exec ztd ztd-config` (or `npx ztd ztd-config` if you prefer npm-style invocation).
|
|
24
|
+
3. Run `pnpm exec ztd model-gen --probe-mode ztd <sql-file> --out <spec-file>` when you want a QuerySpec scaffold from the local DDL snapshot.
|
|
25
|
+
4. Wire repositories to `src/infrastructure/telemetry/repositoryTelemetry.ts` so application code can replace the default telemetry hook.
|
|
26
|
+
5. Provide a SqlClient implementation.
|
|
27
|
+
6. Run tests (`pnpm test` or `npx vitest run`).
|
|
28
|
+
7. Use `ZTD_TEST_DATABASE_URL` for ZTD-owned test and verification workflows.
|
|
29
|
+
8. Use `ztd model-gen --probe-mode live`, `ztd ddl pull`, or `ztd ddl diff` only for explicit target inspection by passing `--url` or a complete `--db-*` flag set.
|
|
30
|
+
9. If you generate migration SQL artifacts, apply them with your deployment tooling instead of `ztd-cli`.
|
|
31
|
+
|
|
32
|
+
If this project was scaffolded with `ztd init --local-source-root <monorepo-root>`, first run `pnpm install` (or `pnpm install --ignore-workspace` when nested under another `pnpm-workspace.yaml`), then `pnpm typecheck`, then `pnpm test`, then `pnpm ztd ztd-config`. For generated QuerySpecs, prefer `pnpm ztd model-gen --probe-mode ztd --import-style relative` so imports keep using the local shim.
|
|
33
|
+
|
|
34
|
+
For schema-change impact checks, `npx ztd query uses` defaults to the `impact` view. Table add / column add checks usually work with the default scan, while table rename / column rename / column type change checks often benefit from `--exclude-generated` so review-only specs under `src/catalog/specs/generated` do not add noise. The flag is optional and does not change the default scan set.
|
|
35
|
+
|
|
36
|
+
If you later switch this scaffold into a layered WebAPI shape, add a prompt-dogfooding guide similar to `PROMPT_DOGFOOD.md` so generic transport requests can be checked for accidental ZTD leakage.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pnpm exec ztd query uses table public.sale_items --exclude-generated
|
|
42
|
+
pnpm exec ztd query uses table public.sale_lines --exclude-generated
|
|
43
|
+
pnpm exec ztd query uses column public.products.title --exclude-generated
|
|
44
|
+
pnpm exec ztd query uses column public.sale_items.quantity --exclude-generated
|
|
45
|
+
pnpm exec ztd query uses table public.sale_lines --view detail --exclude-generated
|
|
46
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Zero Table Dependency WebAPI Project
|
|
2
|
+
|
|
3
|
+
This scaffold separates WebAPI concerns into explicit layers so transport and use-case work do not accidentally inherit persistence-specific rules.
|
|
4
|
+
|
|
5
|
+
Conceptual model:
|
|
6
|
+
- `ztd-cli` implicitly uses only `ZTD_TEST_DATABASE_URL`.
|
|
7
|
+
- Projects often also have a runtime or deployment database setting such as `DATABASE_URL`, but `ztd-cli` does not read it automatically.
|
|
8
|
+
- Any non-ZTD database target must be passed explicitly via `--url` or `--db-*`.
|
|
9
|
+
- `ztd-cli` may generate migration SQL artifacts, but it does not apply them.
|
|
10
|
+
|
|
11
|
+
Quick boundary table:
|
|
12
|
+
- `ZTD_TEST_DATABASE_URL`: owned by `ztd-cli` for ZTD tests and verification
|
|
13
|
+
- `DATABASE_URL`: runtime or deployment concern, not read automatically by `ztd-cli`
|
|
14
|
+
- `--url` / complete `--db-*`: explicit target inspection only
|
|
15
|
+
|
|
16
|
+
Key folders:
|
|
17
|
+
- `src/domain`: domain types and business rules with no direct ZTD dependency
|
|
18
|
+
- `src/application`: use cases and orchestration over domain-facing ports
|
|
19
|
+
- `src/presentation/http`: HTTP handlers, request parsing, and response shaping
|
|
20
|
+
- `src/infrastructure/persistence`: repositories, SQL assets, and QuerySpec wiring
|
|
21
|
+
- `src/sql`, `src/catalog`, `ztd/ddl`: ZTD-owned persistence assets
|
|
22
|
+
- `tests`: smoke tests and test support
|
|
23
|
+
|
|
24
|
+
Prompt dogfooding:
|
|
25
|
+
- See `PROMPT_DOGFOOD.md` when you want to verify that generic WebAPI requests stay out of persistence-specific ZTD guidance unless repository or SQL work is explicitly requested.
|
|
26
|
+
|
|
27
|
+
Next steps:
|
|
28
|
+
1. Update `ztd/ddl/<schema>.sql` if needed.
|
|
29
|
+
2. Run `pnpm exec ztd ztd-config` (or `npx ztd ztd-config` if you prefer npm-style invocation).
|
|
30
|
+
3. Keep `src/domain`, `src/application`, and `src/presentation/http` free from direct SQL or DDL concerns.
|
|
31
|
+
4. Use `pnpm exec ztd model-gen --probe-mode ztd <sql-file> --out <spec-file>` when you want a QuerySpec scaffold from the local DDL snapshot.
|
|
32
|
+
5. Wire repositories to `src/infrastructure/telemetry/repositoryTelemetry.ts` only when you add SQL-backed repository classes.
|
|
33
|
+
6. Provide a SqlClient implementation in `src/infrastructure/db`.
|
|
34
|
+
7. Run tests (`pnpm test` or `npx vitest run`) with `ZTD_TEST_DATABASE_URL` when SQL-backed verification needs a managed test database.
|
|
35
|
+
8. Treat `ddl pull` and `ddl diff` as explicit target inspection commands that require `--url` or a complete `--db-*` flag set.
|
|
36
|
+
9. If you generate migration SQL artifacts, apply them outside `ztd-cli`.
|
|
37
|
+
|
|
38
|
+
If this project was scaffolded with `ztd init --local-source-root <monorepo-root>`, first run `pnpm install` (or `pnpm install --ignore-workspace` when nested under another `pnpm-workspace.yaml`), then `pnpm typecheck`, then `pnpm test`, then `pnpm ztd ztd-config`. For generated QuerySpecs, prefer `pnpm ztd model-gen --probe-mode ztd --import-style relative` so imports keep using the local shim.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
const projectRoot = process.cwd();
|
|
7
|
+
const command = process.argv[2];
|
|
8
|
+
|
|
9
|
+
if (command !== 'test' && command !== 'typecheck' && command !== 'ztd') {
|
|
10
|
+
console.error('local-source guard expects "test", "typecheck", or "ztd".');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (command === 'ztd') {
|
|
15
|
+
const cliEntry = path.resolve(projectRoot, '__LOCAL_SOURCE_ZTD_CLI__');
|
|
16
|
+
const requestedSubcommand = process.argv.slice(3).join(' ').trim() || '(none)';
|
|
17
|
+
if (!existsSync(cliEntry)) {
|
|
18
|
+
console.error(
|
|
19
|
+
[
|
|
20
|
+
'[local-source guard] ztd cannot run against the local source checkout yet.',
|
|
21
|
+
'',
|
|
22
|
+
`What happened:`,
|
|
23
|
+
`- Requested subcommand: ${requestedSubcommand}`,
|
|
24
|
+
`- Project root: ${normalizePath(projectRoot)}`,
|
|
25
|
+
`- The local CLI entry was not found at ${normalizePath(cliEntry)}.`,
|
|
26
|
+
'',
|
|
27
|
+
'Next steps:',
|
|
28
|
+
'1. Build the local CLI package (for example: pnpm --filter @rawsql-ts/ztd-cli build)',
|
|
29
|
+
'2. Confirm this scaffold still points at the intended rawsql-ts monorepo root',
|
|
30
|
+
'3. Re-run pnpm ztd <subcommand>'
|
|
31
|
+
].join('\n')
|
|
32
|
+
);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const cliArgs = process.argv.slice(3);
|
|
37
|
+
const result = spawnSync(process.execPath, [cliEntry, ...cliArgs], {
|
|
38
|
+
cwd: projectRoot,
|
|
39
|
+
stdio: 'inherit',
|
|
40
|
+
shell: false
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Surface execution failures explicitly so local-source dogfooding does not
|
|
44
|
+
// collapse permission, spawn, and signal problems into the same exit code.
|
|
45
|
+
if (result.error) {
|
|
46
|
+
console.error('[local-source guard] Failed to launch the local ztd CLI entry.');
|
|
47
|
+
console.error(`- Message: ${result.error.message}`);
|
|
48
|
+
if (result.error.stack) {
|
|
49
|
+
console.error(result.error.stack);
|
|
50
|
+
}
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (result.signal) {
|
|
55
|
+
console.error('[local-source guard] The local ztd CLI entry was terminated by signal.');
|
|
56
|
+
console.error(`- Signal: ${result.signal}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
process.exit(result.status ?? 1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const workspaceRoot = findAncestorPnpmWorkspaceRoot(projectRoot);
|
|
64
|
+
const installCommand = workspaceRoot ? 'pnpm install --ignore-workspace' : 'pnpm install';
|
|
65
|
+
const rerunCommand = command === 'test' ? 'pnpm test' : 'pnpm typecheck';
|
|
66
|
+
const fallbackCommand = command === 'test' ? 'npx vitest run' : 'npx tsc --noEmit';
|
|
67
|
+
const binaryName = process.platform === 'win32'
|
|
68
|
+
? command === 'test'
|
|
69
|
+
? 'vitest.cmd'
|
|
70
|
+
: 'tsc.cmd'
|
|
71
|
+
: command === 'test'
|
|
72
|
+
? 'vitest'
|
|
73
|
+
: 'tsc';
|
|
74
|
+
const binaryArgs = command === 'test' ? ['run'] : ['--noEmit'];
|
|
75
|
+
const binaryPath = path.join(projectRoot, 'node_modules', '.bin', binaryName);
|
|
76
|
+
const packageChecks = command === 'test'
|
|
77
|
+
? ['vitest/package.json', 'zod/package.json', '@rawsql-ts/sql-contract/package.json']
|
|
78
|
+
: ['typescript/package.json', 'zod/package.json', '@rawsql-ts/sql-contract/package.json'];
|
|
79
|
+
|
|
80
|
+
const resolutionIssues = inspectResolution(packageChecks);
|
|
81
|
+
if (!existsSync(binaryPath) || resolutionIssues.length > 0) {
|
|
82
|
+
printGuidance({
|
|
83
|
+
command,
|
|
84
|
+
installCommand,
|
|
85
|
+
rerunCommand,
|
|
86
|
+
fallbackCommand,
|
|
87
|
+
workspaceRoot,
|
|
88
|
+
binaryPath,
|
|
89
|
+
resolutionIssues
|
|
90
|
+
});
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const result = spawnSync(binaryPath, binaryArgs, {
|
|
95
|
+
cwd: projectRoot,
|
|
96
|
+
stdio: 'inherit',
|
|
97
|
+
shell: process.platform === 'win32'
|
|
98
|
+
});
|
|
99
|
+
process.exit(result.status ?? 1);
|
|
100
|
+
|
|
101
|
+
function inspectResolution(specifiers) {
|
|
102
|
+
const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
|
|
103
|
+
const issues = [];
|
|
104
|
+
|
|
105
|
+
for (const specifier of specifiers) {
|
|
106
|
+
try {
|
|
107
|
+
const resolvedPath = specifier.endsWith('/package.json')
|
|
108
|
+
? resolveInstalledPackageManifest(specifier)
|
|
109
|
+
: projectRequire.resolve(specifier);
|
|
110
|
+
if (!isInsideProject(resolvedPath)) {
|
|
111
|
+
issues.push(`${specifier} resolved outside this scaffold: ${normalizePath(resolvedPath)}`);
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
issues.push(`${specifier} is not installed in this scaffold`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return issues;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function resolveInstalledPackageManifest(specifier) {
|
|
122
|
+
const manifestRelativePath = path.join('node_modules', ...specifier.split('/'));
|
|
123
|
+
const manifestPath = path.join(projectRoot, manifestRelativePath);
|
|
124
|
+
if (!existsSync(manifestPath)) {
|
|
125
|
+
throw new Error(`${specifier} manifest is missing`);
|
|
126
|
+
}
|
|
127
|
+
return manifestPath;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isInsideProject(filePath) {
|
|
131
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
132
|
+
return relativePath.length === 0 || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function normalizePath(filePath) {
|
|
136
|
+
return filePath.replace(/\\/g, '/');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function findAncestorPnpmWorkspaceRoot(rootDir) {
|
|
140
|
+
let cursor = path.resolve(rootDir);
|
|
141
|
+
while (true) {
|
|
142
|
+
const parentDir = path.dirname(cursor);
|
|
143
|
+
if (parentDir === cursor) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
cursor = parentDir;
|
|
147
|
+
if (existsSync(path.join(cursor, 'pnpm-workspace.yaml'))) {
|
|
148
|
+
return cursor;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function printGuidance({
|
|
154
|
+
command,
|
|
155
|
+
installCommand,
|
|
156
|
+
rerunCommand,
|
|
157
|
+
fallbackCommand,
|
|
158
|
+
workspaceRoot,
|
|
159
|
+
binaryPath,
|
|
160
|
+
resolutionIssues
|
|
161
|
+
}) {
|
|
162
|
+
const commandLabel = command === 'test' ? 'pnpm test' : 'pnpm typecheck';
|
|
163
|
+
const lines = [
|
|
164
|
+
`[local-source guard] ${commandLabel} cannot run against this scaffold yet.`,
|
|
165
|
+
'',
|
|
166
|
+
'What happened:',
|
|
167
|
+
`- The local binary was not found at ${normalizePath(binaryPath)} or required packages resolved outside this project.`,
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
if (workspaceRoot) {
|
|
171
|
+
lines.push(`- This project sits under pnpm workspace ${normalizePath(workspaceRoot)}, so pnpm may still be using the parent workspace context.`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (resolutionIssues.length > 0) {
|
|
175
|
+
lines.push('- Resolution details:');
|
|
176
|
+
for (const issue of resolutionIssues) {
|
|
177
|
+
lines.push(` - ${issue}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
lines.push(
|
|
182
|
+
'',
|
|
183
|
+
'Next steps:',
|
|
184
|
+
`1. Run ${installCommand}`,
|
|
185
|
+
`2. Re-run ${rerunCommand}`,
|
|
186
|
+
`3. If pnpm still looks absorbed by the parent workspace, try ${fallbackCommand}`
|
|
187
|
+
);
|
|
188
|
+
console.error(lines.join('\n'));
|
|
189
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Package Scope
|
|
2
|
+
- Applies to `packages/ztd-cli/templates/src`.
|
|
3
|
+
- Governs runtime application code emitted by template generation across both generic and WebAPI-oriented layouts.
|
|
4
|
+
|
|
5
|
+
# Policy
|
|
6
|
+
## REQUIRED
|
|
7
|
+
- Runtime code under `src/` MUST remain independent from `tests/` and `tests/generated/` imports.
|
|
8
|
+
- Runtime code MUST remain independent from ZTD internals.
|
|
9
|
+
- Runtime modules MUST use explicit contracts and deterministic failure surfaces.
|
|
10
|
+
- Domain, application, and presentation layers MUST stay free from direct SQL/DDL ownership when those directories exist.
|
|
11
|
+
|
|
12
|
+
## ALLOWED
|
|
13
|
+
- Runtime modules MAY use project typecheck and filtered test commands for validation.
|
|
14
|
+
|
|
15
|
+
## PROHIBITED
|
|
16
|
+
- Importing test-only helpers into runtime code.
|
|
17
|
+
- Treating generated artifacts as runtime dependencies.
|
|
18
|
+
|
|
19
|
+
# Mandatory Workflow
|
|
20
|
+
- Before committing changes under `src/`, run project typecheck and relevant tests.
|
|
21
|
+
|
|
22
|
+
# Hygiene
|
|
23
|
+
- Keep runtime modules explicit and small enough to preserve contract boundaries.
|
|
24
|
+
|
|
25
|
+
# References
|
|
26
|
+
- Parent policy: [../AGENTS.md](../AGENTS.md)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Package Scope
|
|
2
|
+
- Applies to `packages/ztd-cli/templates/src/application`.
|
|
3
|
+
- Defines application-layer orchestration for WebAPI-oriented scaffolds.
|
|
4
|
+
|
|
5
|
+
# Policy
|
|
6
|
+
## REQUIRED
|
|
7
|
+
- Application modules MUST orchestrate domain-facing ports and policies without embedding transport or SQL details.
|
|
8
|
+
- Validation and command handling MAY live here when it stays independent from persistence mechanics.
|
|
9
|
+
|
|
10
|
+
## PROHIBITED
|
|
11
|
+
- Direct SQL file access.
|
|
12
|
+
- Direct dependence on DDL or QuerySpec implementation details.
|
|
13
|
+
|
|
14
|
+
# Mandatory Workflow
|
|
15
|
+
- Application changes MUST run the relevant typecheck and behavioral tests.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Package Scope
|
|
2
|
+
- Applies to `packages/ztd-cli/templates/src/catalog`.
|
|
3
|
+
- Defines runtime catalog contract boundaries between human-owned specs and runtime wiring.
|
|
4
|
+
|
|
5
|
+
# Policy
|
|
6
|
+
## REQUIRED
|
|
7
|
+
- Catalog entrypoints MUST bind SQL assets, parameter contracts, output contracts, and runtime validation/mapping.
|
|
8
|
+
- `src/catalog/specs` MUST be treated as human-owned contracts.
|
|
9
|
+
- `src/catalog/runtime` MUST implement runtime wiring only.
|
|
10
|
+
- Code in `src/catalog` MUST remain independent from `tests`, `tests/generated`, and `ztd` imports.
|
|
11
|
+
- Each spec MUST be covered by tests for rewrite execution, mapping/validation outcomes, and output shape.
|
|
12
|
+
|
|
13
|
+
## ALLOWED
|
|
14
|
+
- Runtime catalog code MAY add observability hooks where contract behavior is unchanged.
|
|
15
|
+
|
|
16
|
+
## PROHIBITED
|
|
17
|
+
- Changing spec params/DTO contracts without explicit instruction.
|
|
18
|
+
- Runtime dependency on ZTD internals.
|
|
19
|
+
|
|
20
|
+
# Mandatory Workflow
|
|
21
|
+
- Catalog spec or runtime changes MUST run tests that exercise affected specs.
|
|
22
|
+
|
|
23
|
+
# Hygiene
|
|
24
|
+
- Preserve clear separation between `specs` and `runtime` responsibilities.
|
|
25
|
+
|
|
26
|
+
# References
|
|
27
|
+
- Specs contract: [./specs/AGENTS.md](./specs/AGENTS.md)
|
|
28
|
+
- Runtime contract: [./runtime/AGENTS.md](./runtime/AGENTS.md)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Package Scope
|
|
2
|
+
- Applies to `packages/ztd-cli/templates/src/catalog/runtime`.
|
|
3
|
+
- Defines runtime validation, normalization, and row-to-DTO mapping behavior.
|
|
4
|
+
|
|
5
|
+
# Policy
|
|
6
|
+
## REQUIRED
|
|
7
|
+
- Runtime MUST be the only layer that validates unknown input into typed params and validates output contracts.
|
|
8
|
+
- Runtime MUST map snake_case SQL rows into DTO objects using explicit normalization rules.
|
|
9
|
+
- Timestamp normalization MUST use `timestampFromDriver`.
|
|
10
|
+
- Numeric normalization rules MUST be explicit per contract.
|
|
11
|
+
- Runtime helpers (`ensure*`, `map*`) MUST validate before returning values.
|
|
12
|
+
|
|
13
|
+
## ALLOWED
|
|
14
|
+
- Command outputs MAY be scalar identifiers or `void` when the contract output is non-DTO.
|
|
15
|
+
|
|
16
|
+
## PROHIBITED
|
|
17
|
+
- Database I/O in runtime mapping modules.
|
|
18
|
+
- Importing from `tests/` or `tests/generated/`.
|
|
19
|
+
- Defining or editing human-owned contracts in runtime modules.
|
|
20
|
+
|
|
21
|
+
# Mandatory Workflow
|
|
22
|
+
- Runtime changes MUST run tests that cover normalization and validator failure paths.
|
|
23
|
+
|
|
24
|
+
# Hygiene
|
|
25
|
+
- Do not swallow validator errors or silently coerce unsupported values.
|
|
26
|
+
|
|
27
|
+
# References
|
|
28
|
+
- Parent catalog policy: [../AGENTS.md](../AGENTS.md)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Runtime coercions run BEFORE validator schemas.
|
|
2
|
+
// See docs/recipes/mapping-vs-validation.md for pipeline details.
|
|
3
|
+
export function normalizeTimestamp(value: unknown, fieldName?: string): Date {
|
|
4
|
+
const fieldLabel = fieldName?.trim() ? ` for "${fieldName}"` : '';
|
|
5
|
+
|
|
6
|
+
// Preserve valid Date instances while rejecting invalid dates eagerly.
|
|
7
|
+
if (value instanceof Date) {
|
|
8
|
+
if (Number.isNaN(value.getTime())) {
|
|
9
|
+
throw new Error(`Invalid Date value${fieldLabel}.`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Parse driver-returned timestamp strings after trimming transport whitespace.
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
if (!trimmed) {
|
|
18
|
+
throw new Error(`Expected a non-empty timestamp string${fieldLabel}.`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const timestamp = Date.parse(trimmed);
|
|
22
|
+
if (Number.isNaN(timestamp)) {
|
|
23
|
+
throw new Error(`Invalid timestamp string${fieldLabel}: "${value}".`);
|
|
24
|
+
}
|
|
25
|
+
return new Date(timestamp);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const actualType = value === null ? 'null' : typeof value;
|
|
29
|
+
throw new Error(`Expected Date or timestamp string${fieldLabel}, received ${actualType}.`);
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Runtime coercions run BEFORE validator schemas.
|
|
2
|
+
// See docs/recipes/mapping-vs-validation.md for pipeline details.
|
|
3
|
+
export function normalizeTimestamp(value: unknown, fieldName?: string): Date {
|
|
4
|
+
const fieldLabel = fieldName?.trim() ? ` for "${fieldName}"` : '';
|
|
5
|
+
|
|
6
|
+
// Preserve valid Date instances while rejecting invalid dates eagerly.
|
|
7
|
+
if (value instanceof Date) {
|
|
8
|
+
if (Number.isNaN(value.getTime())) {
|
|
9
|
+
throw new Error(`Invalid Date value${fieldLabel}.`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Parse driver-returned timestamp strings after trimming transport whitespace.
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
if (!trimmed) {
|
|
18
|
+
throw new Error(`Expected a non-empty timestamp string${fieldLabel}.`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const timestamp = Date.parse(trimmed);
|
|
22
|
+
if (Number.isNaN(timestamp)) {
|
|
23
|
+
throw new Error(`Invalid timestamp string${fieldLabel}: "${value}".`);
|
|
24
|
+
}
|
|
25
|
+
return new Date(timestamp);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const actualType = value === null ? 'null' : typeof value;
|
|
29
|
+
throw new Error(`Expected Date or timestamp string${fieldLabel}, received ${actualType}.`);
|
|
30
|
+
}
|