@rawsql-ts/ztd-cli 0.16.0 → 0.17.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.
Files changed (50) hide show
  1. package/README.md +33 -20
  2. package/dist/commands/init.d.ts +13 -0
  3. package/dist/commands/init.js +372 -127
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/lint.d.ts +4 -4
  6. package/dist/commands/lint.js +60 -40
  7. package/dist/commands/lint.js.map +1 -1
  8. package/dist/commands/ztdConfig.d.ts +2 -2
  9. package/dist/commands/ztdConfig.js +26 -12
  10. package/dist/commands/ztdConfig.js.map +1 -1
  11. package/dist/utils/optionalDependencies.d.ts +35 -0
  12. package/dist/utils/optionalDependencies.js +96 -0
  13. package/dist/utils/optionalDependencies.js.map +1 -0
  14. package/package.json +16 -9
  15. package/templates/AGENTS.md +36 -309
  16. package/templates/README.md +12 -215
  17. package/templates/dist/ztd-cli/templates/src/db/sql-client.ts +24 -0
  18. package/templates/src/AGENTS.md +26 -0
  19. package/templates/src/catalog/AGENTS.md +37 -0
  20. package/templates/src/catalog/runtime/AGENTS.md +75 -0
  21. package/templates/src/catalog/runtime/_coercions.ts +1 -0
  22. package/templates/src/catalog/runtime/_smoke.runtime.ts +21 -0
  23. package/templates/src/catalog/specs/AGENTS.md +48 -0
  24. package/templates/src/catalog/specs/_smoke.spec.arktype.ts +21 -0
  25. package/templates/src/catalog/specs/_smoke.spec.zod.ts +20 -0
  26. package/templates/src/db/sql-client.ts +5 -5
  27. package/templates/src/jobs/AGENTS.md +26 -0
  28. package/templates/src/jobs/README.md +3 -0
  29. package/templates/src/repositories/AGENTS.md +118 -0
  30. package/templates/src/repositories/tables/AGENTS.md +94 -0
  31. package/templates/src/repositories/tables/README.md +3 -0
  32. package/templates/src/repositories/views/AGENTS.md +25 -0
  33. package/templates/src/repositories/views/README.md +3 -0
  34. package/templates/src/sql/AGENTS.md +77 -0
  35. package/templates/src/sql/README.md +6 -0
  36. package/templates/tests/AGENTS.md +43 -150
  37. package/templates/tests/generated/AGENTS.md +16 -0
  38. package/templates/tests/smoke.test.ts +5 -0
  39. package/templates/tests/smoke.validation.test.ts +34 -0
  40. package/templates/tests/support/AGENTS.md +26 -0
  41. package/templates/tests/support/global-setup.ts +8 -23
  42. package/templates/tests/support/testkit-client.ts +13 -741
  43. package/templates/tsconfig.json +8 -1
  44. package/templates/ztd/AGENTS.md +11 -67
  45. package/templates/ztd/README.md +4 -13
  46. package/templates/ztd/ddl/AGENTS.md +34 -0
  47. package/templates/ztd/ddl/demo.sql +74 -0
  48. package/templates/src/repositories/user-accounts.ts +0 -179
  49. package/templates/tests/user-profiles.test.ts +0 -161
  50. package/templates/tests/writer-constraints.test.ts +0 -32
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.clearOptionalDependencyCache = clearOptionalDependencyCache;
40
+ exports.ensureTestkitCoreModule = ensureTestkitCoreModule;
41
+ exports.ensureAdapterNodePgModule = ensureAdapterNodePgModule;
42
+ exports.ensurePgModule = ensurePgModule;
43
+ exports.ensurePostgresContainerModule = ensurePostgresContainerModule;
44
+ const node_path_1 = __importDefault(require("node:path"));
45
+ const node_module_1 = require("node:module");
46
+ const node_url_1 = require("node:url");
47
+ const moduleCache = new Map();
48
+ async function loadOptionalModule(cacheKey, loader, description, installHint) {
49
+ if (moduleCache.has(cacheKey)) {
50
+ return moduleCache.get(cacheKey);
51
+ }
52
+ const moduleLoader = loader()
53
+ .catch((error) => {
54
+ moduleCache.delete(cacheKey);
55
+ const installNote = installHint ? ` Install it via \`${installHint}\`.` : '';
56
+ const original = error instanceof Error ? ` (${error.message})` : '';
57
+ throw new Error(`${description}${installNote}${original}`);
58
+ });
59
+ moduleCache.set(cacheKey, moduleLoader);
60
+ return moduleLoader;
61
+ }
62
+ function clearOptionalDependencyCache() {
63
+ moduleCache.clear();
64
+ }
65
+ function requireFromWorkspace(specifier) {
66
+ const require = (0, node_module_1.createRequire)(node_path_1.default.resolve(process.cwd(), 'package.json'));
67
+ return require(specifier);
68
+ }
69
+ async function loadAdapterNodePgModule() {
70
+ try {
71
+ return requireFromWorkspace('@rawsql-ts/adapter-node-pg');
72
+ }
73
+ catch (error) {
74
+ // Workspace tests can run before adapter build output exists, so use source entrypoint.
75
+ const workspaceAdapterSrc = node_path_1.default.resolve(process.cwd(), 'packages/adapters/adapter-node-pg/src/index.ts');
76
+ try {
77
+ return (await Promise.resolve(`${(0, node_url_1.pathToFileURL)(workspaceAdapterSrc).href}`).then(s => __importStar(require(s))));
78
+ }
79
+ catch {
80
+ throw error;
81
+ }
82
+ }
83
+ }
84
+ async function ensureTestkitCoreModule() {
85
+ return loadOptionalModule('@rawsql-ts/testkit-core', () => Promise.resolve().then(() => __importStar(require('@rawsql-ts/testkit-core'))), 'This command requires @rawsql-ts/testkit-core so fixtures and schema metadata are available.', 'pnpm add -D @rawsql-ts/testkit-core');
86
+ }
87
+ async function ensureAdapterNodePgModule() {
88
+ return loadOptionalModule('@rawsql-ts/adapter-node-pg', loadAdapterNodePgModule, 'A database adapter (for example @rawsql-ts/adapter-node-pg) is required to execute the rewritten SQL.', 'pnpm add -D @rawsql-ts/adapter-node-pg');
89
+ }
90
+ async function ensurePgModule() {
91
+ return loadOptionalModule('pg', () => Promise.resolve().then(() => __importStar(require('pg'))), 'The SQL lint command needs a PostgreSQL driver such as pg.', 'pnpm add -D pg');
92
+ }
93
+ async function ensurePostgresContainerModule() {
94
+ return loadOptionalModule('@testcontainers/postgresql', () => Promise.resolve().then(() => __importStar(require('@testcontainers/postgresql'))), 'ztd lint wants to spin up a disposable Postgres container via @testcontainers/postgresql.', 'pnpm add -D @testcontainers/postgresql');
95
+ }
96
+ //# sourceMappingURL=optionalDependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optionalDependencies.js","sourceRoot":"","sources":["../../src/utils/optionalDependencies.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,oEAEC;AAwBD,0DAOC;AAED,8DAOC;AAED,wCAOC;AAED,sEAOC;AA5HD,0DAA6B;AAC7B,6CAA4C;AAC5C,uCAAyC;AAEzC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;AAExD,KAAK,UAAU,kBAAkB,CAC/B,QAAgB,EAChB,MAAwB,EACxB,WAAmB,EACnB,WAAmB;IAEnB,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAe,CAAC;IACjD,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,EAAE;SAC1B,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,qBAAqB,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEL,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxC,OAAO,YAAY,CAAC;AACtB,CAAC;AAsCD,SAAgB,4BAA4B;IAC1C,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,oBAAoB,CAAI,SAAiB;IAChD,MAAM,OAAO,GAAG,IAAA,2BAAa,EAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,SAAS,CAAM,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,uBAAuB;IACpC,IAAI,CAAC;QACH,OAAO,oBAAoB,CAAsB,4BAA4B,CAAC,CAAC;IACjF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wFAAwF;QACxF,MAAM,mBAAmB,GAAG,mBAAI,CAAC,OAAO,CACtC,OAAO,CAAC,GAAG,EAAE,EACb,gDAAgD,CACjD,CAAC;QACF,IAAI,CAAC;YACH,OAAO,CAAC,yBAAa,IAAA,wBAAa,EAAC,mBAAmB,CAAC,CAAC,IAAI,uCAAC,CAAwB,CAAC;QACxF,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,uBAAuB;IAC3C,OAAO,kBAAkB,CACvB,yBAAyB,EACzB,GAAG,EAAE,mDAAQ,yBAAyB,GAAC,EACvC,8FAA8F,EAC9F,qCAAqC,CACtC,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,yBAAyB;IAC7C,OAAO,kBAAkB,CACvB,4BAA4B,EAC5B,uBAAuB,EACvB,uGAAuG,EACvG,wCAAwC,CACzC,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,cAAc;IAClC,OAAO,kBAAkB,CACvB,IAAI,EACJ,GAAG,EAAE,mDAAQ,IAAI,GAAC,EAClB,4DAA4D,EAC5D,gBAAgB,CACjB,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,6BAA6B;IACjD,OAAO,kBAAkB,CACvB,4BAA4B,EAC5B,GAAG,EAAE,mDAAQ,4BAA4B,GAAC,EAC1C,2FAA2F,EAC3F,wCAAwC,CACzC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawsql-ts/ztd-cli",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "DB-agnostic scaffolding and DDL helpers for Zero Table Dependency projects",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -22,23 +22,31 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "dependencies": {
25
- "@testcontainers/postgresql": "^10.28.0",
26
25
  "chokidar": "^5.0.0",
27
26
  "commander": "^12.0.0",
28
27
  "diff": "^8.0.3",
29
28
  "fast-glob": "^3.3.3",
30
- "pg": "^8.11.1",
31
- "testcontainers": "^10.28.0",
32
- "@rawsql-ts/adapter-node-pg": "^0.15.1",
33
- "@rawsql-ts/testkit-postgres": "^0.15.1",
34
- "@rawsql-ts/testkit-core": "^0.15.1",
35
29
  "rawsql-ts": "^0.16.0"
36
30
  },
31
+ "peerDependencies": {
32
+ "@rawsql-ts/adapter-node-pg": "^0.15.2"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "@rawsql-ts/adapter-node-pg": {
36
+ "optional": true
37
+ }
38
+ },
37
39
  "devDependencies": {
40
+ "@testcontainers/postgresql": "^10.28.0",
38
41
  "@types/diff": "^5.0.1",
39
42
  "@types/node": "^22.13.10",
43
+ "pg": "^8.11.1",
44
+ "testcontainers": "^10.28.0",
40
45
  "typescript": "^5.8.2",
41
- "vitest": "^4.0.7"
46
+ "vitest": "^4.0.7",
47
+ "@rawsql-ts/adapter-node-pg": "^0.15.2",
48
+ "@rawsql-ts/testkit-core": "^0.15.1",
49
+ "@rawsql-ts/testkit-postgres": "^0.15.1"
42
50
  },
43
51
  "files": [
44
52
  "dist",
@@ -47,7 +55,6 @@
47
55
  "README.md"
48
56
  ],
49
57
  "scripts": {
50
- "prebuild": "pnpm --filter @rawsql-ts/testkit-core build && pnpm --filter @rawsql-ts/testkit-postgres build && pnpm --filter @rawsql-ts/adapter-node-pg build",
51
58
  "build": "tsc -p tsconfig.json",
52
59
  "test": "vitest run",
53
60
  "lint": "eslint src --ext .ts",
@@ -1,325 +1,52 @@
1
- # Appendix: Development Workflow Using Zero Table Dependency (ZTD)
1
+ # Workspace AGENTS
2
2
 
3
- This application uses **Zero Table Dependency (ZTD)** as an internal development workflow for writing, testing, and maintaining SQL logic.
4
- ZTD is not part of the application's runtime behavior; rather, it provides a framework for:
3
+ This repository uses directory-scoped AGENTS.
4
+ Rules live close to where the work happens.
5
5
 
6
- - Maintaining consistent SQL across the project
7
- - Keeping schema metadata and generated artifacts synchronized
8
- - Ensuring deterministic SQL unit tests
9
- - Enabling structured collaboration between humans and AI
6
+ ## Rule precedence
10
7
 
11
- This section documents how ZTD is used inside this repository as a development methodology.
8
+ - The closest "AGENTS.md" to the file being edited has the highest priority.
9
+ - Parent directories provide shared rules.
10
+ - Child directories should only describe deltas.
12
11
 
13
- ---
12
+ ## Global non-negotiables
14
13
 
15
- ## Defaults (important)
14
+ - Do not guess. If something is unknown, state "Not observed" and propose the next check.
15
+ - Do not edit generated artifacts unless explicitly instructed.
16
+ - Respect ownership boundaries: human-owned contracts must not be changed without explicit instruction.
16
17
 
17
- - This project adopts **ZTD as the default development and testing methodology**.
18
- - ZTD is assumed unless explicitly stated otherwise.
19
- - Detailed rules about test execution modes are defined in `templates/tests/AGENTS.md`.
18
+ ## Runtime vs non-runtime
20
19
 
21
- ---
20
+ - Runtime assets live under "src/": executed/loaded by the application.
21
+ - Non-runtime assets live under "ztd/" and parts of "tests/": used for verification and generation.
22
22
 
23
- ## Generated files (important)
23
+ ## Human-owned vs AI-assisted (important)
24
24
 
25
- - `tests/generated/` is auto-generated and must never be committed.
26
- - After cloning the repository (or in a clean environment), run `npx ztd ztd-config`.
27
- - If TypeScript reports missing modules or type errors because `tests/generated/` is missing, run `npx ztd ztd-config`.
25
+ Human-owned (do not change without explicit instruction):
26
+ - "ztd/ddl" (physical schema / DDL)
27
+ - "src/catalog/specs" (query contracts: params + DTO + semantics)
28
+ - "src/sql" (SQL assets; AI may propose patches, but do not rewrite intent)
28
29
 
29
- ---
30
+ AI-assisted (implementation and verification):
31
+ - "src/repositories"
32
+ - "src/catalog/runtime"
33
+ - "tests" (except "tests/generated")
30
34
 
31
- ## TypeScript validation (required)
35
+ Never touch by hand:
36
+ - "tests/generated"
32
37
 
33
- After any code change, TypeScript type checking **must** be performed and must pass.
38
+ ## Where to read next
34
39
 
35
- - Run the project-appropriate typecheck command (e.g. `pnpm typecheck`).
36
- - If generated files are involved, run generators first, then re-run typecheck.
37
- - If typecheck fails, fix errors by root cause, not only the first reported error.
38
- - A change is not considered complete unless typecheck is green.
39
- CI pipelines SHOULD run `npx ztd ztd-config` before typecheck and tests (recommended).
40
+ - "src/catalog/AGENTS.md": catalog layout and contract boundaries
41
+ - "src/repositories/AGENTS.md": repository responsibilities and restrictions
42
+ - "src/sql/AGENTS.md": SQL asset rules
43
+ - "tests/AGENTS.md": ZTD testing rules
44
+ - "ztd/ddl/AGENTS.md": DDL authoring rules
40
45
 
41
- Rationale:
42
- In ZTD-based development, many schema or SQL inconsistencies surface first as TypeScript errors via generated row maps and DTOs.
43
- Type checking is a primary correctness signal, not an optional step.
46
+ ## Test environment guarantee (important)
44
47
 
45
- ---
48
+ - This workspace MUST be test-runnable immediately after initialization.
49
+ - `pnpm test` (or equivalent) must not fail due to missing configuration.
50
+ - Test runner configuration (e.g. vitest.config.ts) is considered part of the template contract.
46
51
 
47
- ## ZTD Implementation Guide (src/)
48
-
49
- The `src/` directory should contain pure TypeScript logic that operates on the row interfaces generated by `tests/generated/ztd-row-map.generated.ts`. Tests should import the row map, repositories should import DTOs, and fixtures must stay under `tests/`. Keep production code decoupled from the generated row map to preserve the distinction between implementation and test scaffolding.
50
-
51
- ### Runtime dependency boundaries (important)
52
-
53
- - Code under `src/` MUST NOT import anything from `tests/` or `tests/generated/`.
54
- - Generated row-maps are test-only artifacts and MUST NEVER influence runtime behavior.
55
- - Mapper and writer runtime utilities MUST NOT depend on ZTD internals or generated helpers.
56
- - All schema compatibility checks (column existence, enum coverage, forbidden columns, etc.) MUST be enforced in tests, never in production code.
57
-
58
- ### Repository Classes: What to Care About
59
-
60
- #### Scope and Responsibility
61
- - Repository classes are responsible for executing SQL and returning query results.
62
- - Avoid embedding business logic, thresholds, or data reshaping inside repositories.
63
- - Treat repositories as thin adapters over SQL.
64
-
65
- #### Mandatory testing rule (important)
66
-
67
- Whenever a repository class is created or modified, corresponding tests **must** be created or updated.
68
-
69
- Rules:
70
- - Every public repository method must be covered by tests.
71
- - Tests must call repository methods, not raw SQL files or SQL strings.
72
- - ZTD fixtures are the only allowed source of database state in tests.
73
- - A repository change without tests is considered incomplete.
74
- - Every repository or test modification must be followed by `pnpm --filter <package> test` (replace `<package>` with the template package name).
75
- - `tests/support/global-setup.ts` already uses `@testcontainers/postgresql`, so the suite stands up a Postgres container automatically whenever `DATABASE_URL` is absent.
76
- - If the suite fails, fix the root cause and rerun the command until it passes before considering the repository change complete.
77
-
78
- Rationale:
79
- ZTD derives much of its value from deterministic, repository-level tests.
80
- Without tests, schema drift and SQL inconsistencies cannot be detected.
81
-
82
- #### SQL Management
83
- - Keep every SELECT statement in a dedicated `.sql` file under `src/sql/` (match the repository name, e.g. `src/sql/user-accounts.sql`).
84
- - Load the SQL via `fs.readFileSync` or similar helpers so the repository never embeds long SQL strings inline.
85
- - Inline SQL is forbidden unless a human explicitly requests an override; follow the `.sql` file convention by default.
86
- - Repository classes should reference those SQL files; the file name should match the repository class or the query method to keep the code/spec alignment clear.
87
-
88
- #### Specifications and Documentation
89
- - If a markdown file with the same base name as the repository or SQL exists, read it before implementation.
90
- - Such files may contain repository-local specifications (e.g. decision tables, thresholds, request/response notes).
91
- - Naming should be aligned (e.g. `FooRepository.ts`, `foo.sql`, `foo.md`).
92
-
93
- #### Request and Response Contracts
94
- - Be explicit about request parameters (types, nullability, constraints).
95
- - Be explicit about response shape (columns, ordering, cardinality).
96
- - Prefer documenting contracts in the repository-local markdown file rather than code comments when they are non-trivial.
97
-
98
- ### SqlClient lifecycle policy (important)
99
-
100
- - When using `src/db/sql-client.ts`, prefer a shared `SqlClient` per worker process (singleton).
101
- - Avoid creating a new database connection for every query or test case.
102
- - Do not share a live connection across parallel workers; each worker should own its own shared client or pool.
103
- - If you need strict isolation, create a dedicated client for that scope and close it explicitly.
104
-
105
- ### Repository SQL and DTO policy (important)
106
-
107
- - Repository SQL must return application-facing DTO shapes.
108
- - SQL SELECT statements should alias columns to camelCase and match the repository return types.
109
- - Do not introduce intermediate `*Row` types when SQL already returns DTO-compatible shapes.
110
- - Define separate Row types only when SQL intentionally returns database-shaped (snake_case) rows, and always convert them explicitly.
111
-
112
- ---
113
-
114
- ### Mapper + writer guardrails (template-specific)
115
-
116
- - In this project, `src/repositories/user-accounts.ts` is the authoritative mapper for the columns defined by the DDL; it MUST enumerate those columns explicitly so downstream logic never infers metadata at runtime.
117
- - Writer helpers in the same module MUST emit SQL for `public.user_account` only and MUST remain limited to the explicit insert/update/delete helpers shown there; DO NOT introduce ad-hoc schema discovery.
118
- - `tests/writer-constraints.test.ts` MUST consume `userAccountWriterColumnSets` together with `tests/generated/ztd-row-map.generated.ts` so CUD callers only reference columns that exist on `public.user_account`.
119
- - When the schema of `public.user_account` changes, update `src/repositories/user-accounts.ts` column metadata, keep `tests/writer-constraints.test.ts` expectations aligned, and re-run `npx ztd ztd-config` so the generated row map stays synchronized with the tests.
120
-
121
- #### Writer safety contract (important)
122
-
123
- - Allowed:
124
- - Insert, update, and delete helpers tied to a single table with explicitly enumerated column sets.
125
- - Explicit `RETURNING` clauses that list permitted columns.
126
- - Patch-style updates that only touch writable columns listed in `userAccountWriterColumnSets`.
127
- - Forbidden:
128
- - Generic writers that accept arbitrary table or column names.
129
- - Runtime schema or enum discovery (e.g., querying `information_schema`) to drive writer column lists.
130
- - Writers that embed joins or subqueries beyond simple `RETURNING` clauses.
131
- If these constraints are insufficient, write the SQL manually.
132
-
133
- #### Mapper strictness policy
134
-
135
- - Mapping is strict by default: SQL must return exactly the DTO-shaped results that `src/repositories/user-accounts.ts` exposes; missing or mismatched columns are bugs that tests MUST surface.
136
- - Non-strict behaviors (coercions, key transforms, etc.) MUST be enabled explicitly via named presets or configuration; relying on implicit or silent defaults is prohibited.
137
-
138
- ### Sequence / identity column policy (important)
139
-
140
- - Sequence / identity columns (auto-generated IDs) are infrastructure concerns.
141
- - Do not explicitly assign values to sequence / identity columns in `INSERT` statements unless explicitly instructed.
142
- - Repository method inputs should omit sequence / identity columns by default.
143
- - Only treat an ID as input data when it represents a business rule (e.g. natural keys, externally assigned IDs).
144
-
145
- ### No test-driven fallbacks in production code (important)
146
-
147
- - Do not add fallbacks in `src/` that exist only to accommodate ZTD/testkit/rewriter limitations.
148
- - If a query fails to be rewritten into ZTD form, do not change runtime behavior to compensate.
149
- - Report tooling issues with minimal reproduction and expected behavior.
150
-
151
- Rationale:
152
- Production code must not diverge from intended SQL semantics due to tooling constraints.
153
-
154
- ---
155
-
156
- ## ZTD Test Guide (tests/)
157
-
158
- Testing under ZTD follows dedicated, directory-scoped rules.
159
-
160
- - Test design, execution mode selection, and constraints are defined in:
161
- - `templates/tests/AGENTS.md`
162
- - Tests validate repository behavior and returned DTOs.
163
- - Raw SQL files or SQL strings must not be tested directly.
164
-
165
- ---
166
-
167
- # ZTD Directory Layout
168
-
169
- ```
170
- /ztd
171
- /ddl
172
- *.sql <- physical schema definitions
173
-
174
- README.md <- documentation for the layout
175
- AGENTS.md <- combined guidance for DDL
176
-
177
- /src <- application & repository logic
178
- /tests <- ZTD tests, fixtures, row-maps
179
- ```
180
-
181
- Only `ztd/ddl` is part of the template contract. Do not create or assume any other `ztd` subdirectories unless the project explicitly adds them.
182
-
183
- The file `tests/generated/ztd-layout.generated.ts` ensures ZTD CLI always points to the correct directories.
184
-
185
- ---
186
-
187
- # Protected directories and edit ownership (important)
188
-
189
- - DDL editing is human-led: `ztd/ddl/`
190
- - `ztd/ddl` is the sole human-owned directory inside `/ztd`; other directories must not be assumed or created without explicit instructions.
191
- - Application code is shared ownership: `src/`
192
- - Tests are shared ownership: `tests/`
193
- - Detailed test constraints live in `templates/tests/AGENTS.md`.
194
-
195
- Additionally:
196
- - Never modify `ztd/AGENTS.md` or `ztd/README.md` without explicit instruction.
197
- - When changes are required in human-led directories, prefer proposing a patch and explaining the impact before applying it.
198
-
199
- ---
200
-
201
- # Principles of ZTD in This Repository
202
-
203
- ### 1. Humans own the definitions
204
- - Physical schema (DDL)
205
- - Repository interfaces
206
-
207
- ### 2. AI assists with implementation
208
- - Generating repository SQL
209
- - Updating fixtures
210
- - Producing intermediate TypeScript structures
211
- - Ensuring SQL adheres to DDL
212
-
213
- ### 3. ZTD enforces consistency
214
- ZTD tests verify that:
215
- - SQL logic matches DDL shapes
216
-
217
- If anything diverges, ZTD failures surface immediately and deterministically.
218
-
219
- ---
220
-
221
- # Development Workflows
222
-
223
- Different types of changes start from different entry points. Use the workflow appropriate for your situation.
224
-
225
- ---
226
-
227
- # Workflow A - Starting From DDL Changes
228
- Modifying tables, columns, constraints, indexes.
229
-
230
- 1. Edit DDL files in `ztd/ddl/`.
231
- 2. Run `npx ztd ztd-config`.
232
- 3. Update repository SQL to match the new schema.
233
- 4. Update fixtures if result shapes changed.
234
- 5. Run tests.
235
-
236
- Flow: DDL to Repository SQL to Fixtures and Tests to Application
237
-
238
- ---
239
-
240
- # Workflow B - Starting From Repository Interface Changes
241
- Changing method signatures, adding new repository methods, etc.
242
-
243
- 1. Modify the repository interface or implementation in `/src`.
244
- 2. Use AI assistance to generate or update the SQL implementation.
245
- 3. If the generated SQL conflicts with DDL or other human-maintained references, update the authoritative source first.
246
- 4. Run ZTD tests.
247
- 5. Regenerate config if SQL output shape changed.
248
-
249
- Flow: Interface to SQL to Tests
250
-
251
- ---
252
-
253
- # Workflow C - Starting From Repository SQL Logic Changes
254
- Bug fixes, refactoring, rewriting queries.
255
-
256
- 1. Edit SQL inside the repository.
257
- 2. Run ZTD tests.
258
- 3. If intended behavior changes, coordinate any necessary DDL updates before adjusting dependent code.
259
- 4. Update fixtures as needed.
260
- 5. Regenerate config if result shape changed.
261
-
262
- Flow: SQL to Tests
263
-
264
- ---
265
-
266
- # Combined Real-World Examples
267
-
268
- - Adding a new contract state: DDL to SQL to config to tests
269
- - Adding a new table: DDL to SQL to fixtures/tests
270
- - Fixing business logic: SQL to tests
271
-
272
- ZTD ensures the development always converges into a consistent, validated workflow.
273
-
274
- ---
275
-
276
- # Human Responsibilities
277
-
278
- Humans maintain:
279
-
280
- - Schema definitions (`ztd/ddl`)
281
- - Repository interfaces and architectural decisions
282
- - Acceptance and review of AI-generated patches
283
-
284
- Humans decide what is correct.
285
-
286
- ---
287
-
288
- # AI Responsibilities
289
-
290
- AI must:
291
-
292
- - Use DDL as the physical structure constraint and never assume any additional `ztd` directories exist unless explicitly added.
293
- - Generate SQL consistent with DDL.
294
- - Update fixtures when needed.
295
- - Never modify `ztd/AGENTS.md` or `ztd/README.md` without explicit instruction.
296
-
297
- AI decides how to implement, but not what is correct.
298
-
299
- ---
300
-
301
- # ZTD CLI Responsibilities
302
-
303
- ZTD CLI:
304
-
305
- - Parses DDL to compute schema shapes
306
- - Rewrites SQL via CTE shadowing for testing
307
- - Generates `ztd-row-map.generated.ts`
308
- - Enables deterministic, parallel SQL unit tests
309
-
310
- ZTD is the verification engine that validates correctness beyond static typing.
311
-
312
- ---
313
-
314
- # Summary
315
-
316
- This appendix documents how ZTD is used strictly as an internal implementation and maintenance guide.
317
- It does not affect the runtime behavior of the application.
318
- Its purpose is ensuring:
319
-
320
- - Schema integrity
321
- - SQL correctness
322
- - Domain consistency
323
- - Reliable AI-assisted development
324
-
325
- With ZTD, humans define the meaning, AI writes the implementation, and tests guarantee correctness.
52
+ If tests fail due to missing config, this is a template defect, not a user error.