create-qs 0.8.26 → 0.8.29
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 +10 -3
- package/index.js +8 -2
- package/package.json +1 -1
- package/template/default/.quicksilver/manual/en-US/00-setup.md +2 -2
- package/template/default/.quicksilver/manual/zh-CN/00-setup.md +2 -2
- package/template/default/.quicksilver/manual/zh-TW/00-setup.md +2 -2
- package/template/default/AGENTS.md +49 -34
- package/template/default/package.json +10 -8
- package/template/default/pnpm-workspace.yaml +6 -6
- package/template/default/quicksilver.yaml +27 -0
- package/template/default/run/api/config/README.md +63 -20
- package/template/default/run/api/config/application-dev.yaml +6 -1
- package/template/default/run/api/config/application-h2.yaml +2 -7
- package/template/default/run/api/config/application-mariadb.yaml +4 -9
- package/template/default/run/api/config/application-mssql.yaml +4 -9
- package/template/default/run/api/config/application-oracle.yaml +2 -7
- package/template/default/run/api/config/application-postgresql.yaml +4 -9
- package/template/default/run/api/config/application-fresh.yaml +0 -23
package/README.md
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
用一条命令创建全栈 Quicksilver 项目。
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
npm create qs
|
|
9
|
+
npm create qs@latest
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
命令中的 `@latest` 不能省略。省略时,如果本机全局安装过 `create-qs`,或者当前目录所属的项目依赖了它,npm 会直接运行已有的那一份,不检查 registry 上是否有更新的版本。
|
|
13
|
+
|
|
12
14
|
这一条命令请使用 npm,不要使用 pnpm。自 pnpm 11 起,`pnpm create` 会跳过发布不足 24 小时的版本(`minimumReleaseAge`),且不给出任何提示,当天发布的脚手架会被静默替换为较早的版本。npm 默认没有这一限制。项目创建完成后,其余操作一律使用 pnpm。
|
|
13
15
|
|
|
14
16
|
脚手架发布在公网 npmjs 上,未做任何配置的机器即可直接运行。它会询问项目及其第一个模块的若干问题,然后生成一个可以直接运行的全栈项目,包括 Kotlin/Spring Boot 后端、Preact/TypeScript 前端、Gradle Wrapper,以及文件型 H2 开发数据库。
|
|
@@ -50,9 +52,11 @@ pnpm dev
|
|
|
50
52
|
用一個指令建立全端 Quicksilver 專案。
|
|
51
53
|
|
|
52
54
|
```bash
|
|
53
|
-
npm create qs
|
|
55
|
+
npm create qs@latest
|
|
54
56
|
```
|
|
55
57
|
|
|
58
|
+
指令中的 `@latest` 不可省略。省略時,如果本機全域安裝過 `create-qs`,或者目前目錄所屬的專案相依於它,npm 會直接執行已有的那一份,不檢查 registry 上是否有更新的版本。
|
|
59
|
+
|
|
56
60
|
這一個指令請使用 npm,不要使用 pnpm。自 pnpm 11 起,`pnpm create` 會略過發布不足 24 小時的版本(`minimumReleaseAge`),且不會給出任何提示,當天發布的鷹架會被默默替換為較早的版本。npm 預設沒有這項限制。專案建立完成後,其餘操作一律使用 pnpm。
|
|
57
61
|
|
|
58
62
|
鷹架發布在公開的 npmjs 上,未做任何設定的電腦即可直接執行。它會詢問專案及其第一個模組的幾個問題,然後產生一個可以直接執行的全端專案,包括 Kotlin/Spring Boot 後端、Preact/TypeScript 前端、Gradle Wrapper,以及檔案型 H2 開發資料庫。
|
|
@@ -93,9 +97,12 @@ pnpm dev
|
|
|
93
97
|
Create a full-stack Quicksilver project with a single command.
|
|
94
98
|
|
|
95
99
|
```bash
|
|
96
|
-
npm create qs
|
|
100
|
+
npm create qs@latest
|
|
97
101
|
```
|
|
98
102
|
|
|
103
|
+
Keep the `@latest`. Without it, npm runs any `create-qs` already installed globally or in the
|
|
104
|
+
project that contains the current directory, and does not check the registry for a newer version.
|
|
105
|
+
|
|
99
106
|
Use npm for this one command, not pnpm. Since pnpm 11, `pnpm create` skips any version published
|
|
100
107
|
less than 24 hours ago (`minimumReleaseAge`) and does not report it, so a scaffolder released the
|
|
101
108
|
same day is silently replaced by an older one. npm applies no such delay by default. Everything
|
package/index.js
CHANGED
|
@@ -646,6 +646,12 @@ async function inputBoolean(options, initial) {
|
|
|
646
646
|
}
|
|
647
647
|
var { Input } = enquirer;
|
|
648
648
|
var TextPrompt = class extends Input {
|
|
649
|
+
async submit() {
|
|
650
|
+
if (this.options.cancelOnEmpty && String(this.value ?? "").trim() === "") {
|
|
651
|
+
return this.cancel();
|
|
652
|
+
}
|
|
653
|
+
return super.submit();
|
|
654
|
+
}
|
|
649
655
|
async close() {
|
|
650
656
|
try {
|
|
651
657
|
await super.close();
|
|
@@ -1970,7 +1976,7 @@ async function processFiles(options) {
|
|
|
1970
1976
|
variables.set("WEB_PACKAGE_NAME", options.webModulePackage);
|
|
1971
1977
|
variables.set("API_PACKAGE", options.apiPackage);
|
|
1972
1978
|
variables.set("API_ARTIFACT_ID", options.apiArtifactId);
|
|
1973
|
-
variables.set("QUICKSILVER_VERSION", "0.8.
|
|
1979
|
+
variables.set("QUICKSILVER_VERSION", "0.8.29");
|
|
1974
1980
|
variables.set("MODULE_ID", randomUUID());
|
|
1975
1981
|
variables.set("DB_PREFIX", toDbPrefix(options.name));
|
|
1976
1982
|
variables.set("JSONS_LOCALE", options.jsonsLocale);
|
|
@@ -2033,7 +2039,7 @@ if (process.argv.some((arg) => arg === "--version" || arg === "-v")) {
|
|
|
2033
2039
|
console.log(getCliVersion());
|
|
2034
2040
|
process.exit(0);
|
|
2035
2041
|
}
|
|
2036
|
-
var program = new Command().name("create-qs").description("Create a new Quicksilver application").version("0.8.
|
|
2042
|
+
var program = new Command().name("create-qs").description("Create a new Quicksilver application").version("0.8.29", "-v, --version").argument("[project-name]", "Name of the project").option("-c, --module-code <code>", "Full module code (e.g., power_crm.sales)").option("-d, --module-directory <directory>", "Module directory name (e.g., sales)").option("-n, --module-namespace <code>", "Prefix of unit/table, defaults to the initials of the module code (e.g., pcs)").option("-p, --api-package <package>", "JVM package for Kotlin files (e.g., com.company.crm)").option("-a, --api-artifact-id <artifactId>", "Module artifact ID in repository (e.g., power-crm-module-sales)").option("-w, --web-module-package <package>", "Web module package name (e.g., @powercrm/module-sales-web)").option("-m, --modules <codes>", "Modules to depend on, comma separated (e.g., quicksilver.org)").option("--module-menu <name>", "Create the module's top-level menu in the left nav, with this label").option("--no-module-menu", "Do not create a top-level menu").option("--jsons-locale <locale>", "Language of the display texts in data files: zh-CN or zh-TW. Changing it later means rewriting every data file").option("-y, --yes", "Skip prompts and use defaults").action(async (projectName, options) => {
|
|
2037
2043
|
applyPromptTexts();
|
|
2038
2044
|
console.log(chalk4.cyan(`
|
|
2039
2045
|
${t("banner")}`));
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ This chapter is committed with the project. The other chapters of the manual app
|
|
|
12
12
|
| Node.js | **`>=22.13.0`** | The minimum version pnpm 11 requires |
|
|
13
13
|
| pnpm | **11** | pnpm is required, npm and yarn are not supported. Workspaces, catalogs and `allowBuilds` all depend on pnpm.
|
|
14
14
|
| Gradle | No installation needed | The project ships the Gradle Wrapper (`./gradlew`), which downloads Gradle on first run |
|
|
15
|
-
| Database | No installation needed | A file-based H2 database is used by default. To use another database, see [01 Getting Started](01-getting-started.md#
|
|
15
|
+
| Database | No installation needed | A file-based H2 database is used by default. To use another database, see [01 Getting Started](01-getting-started.md#development-instances) |
|
|
16
16
|
|
|
17
17
|
## Basic setup
|
|
18
18
|
|
|
@@ -145,7 +145,7 @@ Keep the following two points in mind:
|
|
|
145
145
|
|
|
146
146
|
## Next steps
|
|
147
147
|
|
|
148
|
-
After dependencies are installed, the other chapters of the manual appear in this directory. Start with the [table of contents](README.md), then read [01 Getting Started](01-getting-started.md), which explains the options chosen when creating a project, the common commands, and
|
|
148
|
+
After dependencies are installed, the other chapters of the manual appear in this directory. Start with the [table of contents](README.md), then read [01 Getting Started](01-getting-started.md), which explains the options chosen when creating a project, the common commands, and the development instances with their databases.
|
|
149
149
|
|
|
150
150
|
On first use, run `pnpm qs sources` once. It downloads the platform's API documentation, data files and the frontend `.d.ts` files into `.quicksilver/generated/`, which later chapters of the manual refer to in many places.
|
|
151
151
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
| Node.js | **`>=22.13.0`** | pnpm 11 要求的最低版本 |
|
|
13
13
|
| pnpm | **11** | 必须使用 pnpm,不支持 npm 与 yarn。workspace、catalog、`allowBuilds` 均依赖 pnpm。
|
|
14
14
|
| Gradle | 无需安装 | 项目自带 Gradle Wrapper(`./gradlew`),首次运行时自动下载 |
|
|
15
|
-
| 数据库 | 无需安装 | 默认使用文件型 H2 数据库。使用其他数据库见 [01 快速入门](01-getting-started.md
|
|
15
|
+
| 数据库 | 无需安装 | 默认使用文件型 H2 数据库。使用其他数据库见 [01 快速入门](01-getting-started.md#开发实例) |
|
|
16
16
|
|
|
17
17
|
## 基础设置
|
|
18
18
|
|
|
@@ -145,7 +145,7 @@ power-crm/
|
|
|
145
145
|
|
|
146
146
|
## 下一步
|
|
147
147
|
|
|
148
|
-
安装依赖后,本目录下会出现手册的其余章节。建议先阅读[手册目录](README.md),再阅读 [01 快速入门](01-getting-started.md)
|
|
148
|
+
安装依赖后,本目录下会出现手册的其余章节。建议先阅读[手册目录](README.md),再阅读 [01 快速入门](01-getting-started.md),其中介绍创建项目时各选项的含义、常用命令以及开发实例与数据库。
|
|
149
149
|
|
|
150
150
|
首次使用时建议执行一次 `pnpm qs sources`,将平台的接口文档、数据文件与前端 `.d.ts` 下载到 `.quicksilver/generated/`,手册后续多处会引用其中的内容。
|
|
151
151
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
| Node.js | **`>=22.13.0`** | pnpm 11 要求的最低版本 |
|
|
13
13
|
| pnpm | **11** | 必須使用 pnpm,不支援 npm 與 yarn。workspace、catalog、`allowBuilds` 均依賴 pnpm。
|
|
14
14
|
| Gradle | 無需安裝 | 專案內建 Gradle Wrapper(`./gradlew`),首次執行時自動下載 |
|
|
15
|
-
| 資料庫 | 無需安裝 | 預設使用檔案型 H2 資料庫。使用其他資料庫請參閱 [01 快速入門](01-getting-started.md
|
|
15
|
+
| 資料庫 | 無需安裝 | 預設使用檔案型 H2 資料庫。使用其他資料庫請參閱 [01 快速入門](01-getting-started.md#開發實例) |
|
|
16
16
|
|
|
17
17
|
## 基本設定
|
|
18
18
|
|
|
@@ -145,7 +145,7 @@ power-crm/
|
|
|
145
145
|
|
|
146
146
|
## 下一步
|
|
147
147
|
|
|
148
|
-
安裝相依套件後,本目錄下會出現手冊的其餘章節。建議先閱讀[手冊目錄](README.md),再閱讀 [01 快速入門](01-getting-started.md)
|
|
148
|
+
安裝相依套件後,本目錄下會出現手冊的其餘章節。建議先閱讀[手冊目錄](README.md),再閱讀 [01 快速入門](01-getting-started.md),其中介紹建立專案時各選項的含義、常用指令以及開發實例與資料庫。
|
|
149
149
|
|
|
150
150
|
首次使用時建議執行一次 `pnpm qs sources`,將平台的 API 文件、資料檔與前端 `.d.ts` 下載到 `.quicksilver/generated/`,手冊後續多處會引用其中的內容。
|
|
151
151
|
|
|
@@ -103,9 +103,10 @@ can be started; you rarely touch it.
|
|
|
103
103
|
Project scripts (see `scripts` in `package.json`; the database dialect scripts live there too):
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
pnpm dev # Full dev environment (API + web), ports 6286 / 6288
|
|
107
|
-
pnpm dev:
|
|
108
|
-
pnpm dev:fresh #
|
|
106
|
+
pnpm dev # Full dev environment (API + web), ports 6286 / 6288 in the main checkout
|
|
107
|
+
pnpm dev:ai # The instance for AI agents, with ports and a database of its own
|
|
108
|
+
pnpm dev:fresh # An instance whose own database is rebuilt from init and demo data at every start
|
|
109
|
+
pnpm qs dev --list # Every instance of this workspace, its ports and whether it is running
|
|
109
110
|
pnpm build # Full build (backend + frontend)
|
|
110
111
|
pnpm test:api # Backend tests
|
|
111
112
|
pnpm lint # ESLint (pnpm lint:fix to autofix)
|
|
@@ -173,32 +174,43 @@ you are unsure what a target would actually do.
|
|
|
173
174
|
|
|
174
175
|
## Development servers and ports
|
|
175
176
|
|
|
176
|
-
**An AI agent starts `pnpm dev:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
`run/api/config/application-<dialect>.yaml
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
and
|
|
177
|
+
**An AI agent starts `pnpm dev:ai`, never `pnpm dev` or `pnpm dev:fresh`.**
|
|
178
|
+
|
|
179
|
+
Every workspace, the main checkout or a git worktree, runs its own development instances side by
|
|
180
|
+
side, each with its own ports and its own database. `pnpm dev` and `pnpm dev:fresh` belong to the
|
|
181
|
+
person you are working with, in every workspace. They may well be running already, and the dev
|
|
182
|
+
database keeps their data between starts: with `auto-init.draft-sync: true`, every start runs the
|
|
183
|
+
upgrade drafts that changed since the last one. Starting or restarting it yourself interrupts them
|
|
184
|
+
and runs your half-finished drafts against their data, so taking it over does not just steal a port.
|
|
185
|
+
|
|
186
|
+
`pnpm dev:ai` is the instance for you: ports and a database of its own, side by side with theirs.
|
|
187
|
+
`pnpm qs dev --list` shows every instance of the workspace with its ports and whether it is running.
|
|
188
|
+
To check a database dialect, start its instance, such as `pnpm dev:postgresql`, after filling in the
|
|
189
|
+
placeholders in `run/api/config/application-<dialect>.yaml`.
|
|
190
|
+
|
|
191
|
+
Rules:
|
|
192
|
+
|
|
193
|
+
- **`dev:ai` ports already taken?** Another session in this workspace is using it. Do not stop that
|
|
194
|
+
process: start `pnpm dev:ai2` instead, and ask the person you work with when both are taken. Point
|
|
195
|
+
the test commands at the instance you started: `pnpm qs test verify --instance ai2`,
|
|
196
|
+
`pnpm qs test unit-smoke <unit> --instance ai2`.
|
|
197
|
+
- **Add `--fresh` the first time you start `dev:ai` or `dev:ai2` in a session**, as in
|
|
198
|
+
`pnpm dev:ai --fresh`, and leave it out on later restarts. The database belongs to this workspace
|
|
199
|
+
and instance, but one workspace is used by several sessions in turn, so it may still hold what an
|
|
200
|
+
earlier session left. Restarts within the session go without `--fresh`, so that your own draft
|
|
201
|
+
changes pass through draft sync as they will for others.
|
|
202
|
+
- **Treat the databases of the dialect instances as scratch.** The person you work with and you
|
|
203
|
+
share them, anyone may rebuild them at any time, so keep nothing there you need. Add `--fresh`
|
|
204
|
+
the first time you start a dialect instance in a session, as in `pnpm dev:postgresql --fresh`,
|
|
205
|
+
and again after changing its database by hand. One exception: to check a DDL command in a draft
|
|
206
|
+
(a column type change, a rename), the database has to exist from before the change, and the start
|
|
207
|
+
after editing the draft goes without `--fresh`. A fresh install runs init and skips the drafts,
|
|
208
|
+
so the command would never run.
|
|
199
209
|
- **Rebuild when the database no longer matches the branch.** After switching branches, or when
|
|
200
210
|
earlier experiments left the database in a state you cannot explain, start once with
|
|
201
|
-
`pnpm dev:
|
|
211
|
+
`pnpm dev:ai --fresh`. Draft sync never undoes a change that was taken out of a draft.
|
|
212
|
+
- **Stop the server you started.** Especially after Playwright: leaving it running holds the ports
|
|
213
|
+
and the database.
|
|
202
214
|
|
|
203
215
|
## Signing in locally
|
|
204
216
|
|
|
@@ -220,13 +232,16 @@ platform's own specs and for yours under `test/e2e/scenarios/`, which start out
|
|
|
220
232
|
## Looking at the development data
|
|
221
233
|
|
|
222
234
|
The profile file is the source of truth for where the data actually lives. Read
|
|
223
|
-
`run/api/config/application-dev.yaml` (or `application-<dialect>.yaml` for whichever
|
|
224
|
-
started) and take the datasource from there
|
|
225
|
-
|
|
235
|
+
`run/api/config/application-dev.yaml` (or `application-<dialect>.yaml` for whichever instance you
|
|
236
|
+
started) and take the datasource from there. Paths in it are relative to `run/api`, which is the
|
|
237
|
+
working directory of the API process. The database name then gets the suffix of the instance, which
|
|
238
|
+
`pnpm qs dev --list` shows: in a git worktree and for instances such as `ai`, the name in the file is
|
|
239
|
+
followed by `_worktree<slot>` and `_ai`.
|
|
226
240
|
|
|
227
|
-
For the default H2 profiles that means a file
|
|
228
|
-
`
|
|
229
|
-
connect with your usual client using the host, port, user and password from that
|
|
241
|
+
For the default H2 profiles that means a file, `run/api/local/data/h2/dev` for `pnpm dev` in the main
|
|
242
|
+
checkout and `dev_ai` next to it for `pnpm dev:ai`, which you can open with any H2 client. For the
|
|
243
|
+
other dialects, connect with your usual client using the host, port, user and password from that
|
|
244
|
+
same file.
|
|
230
245
|
|
|
231
246
|
The development database is kept between starts. With `auto-init.draft-sync: true`, every start runs
|
|
232
247
|
each module draft `data/upgrade/draft.jsons` that changed since the last start, and data entered by hand
|
|
@@ -256,7 +271,7 @@ installs only. Imperative commands in a draft (`@sql`,
|
|
|
256
271
|
`$update`, `$delete` ...) run once per `$key`; to run a changed one again, give it a new `$key`.
|
|
257
272
|
`$place` is the exception: it runs again whenever its draft runs. To rebuild the database from the
|
|
258
273
|
data files under `data/init/` and `data/demo/`, add `--fresh` to the start command for one start
|
|
259
|
-
(`pnpm dev:
|
|
274
|
+
(`pnpm dev:ai --fresh`). It changes no config file, and the next start without it keeps the data again.
|
|
260
275
|
|
|
261
276
|
## Development skills
|
|
262
277
|
|
|
@@ -10,15 +10,17 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"// --- start dev servers -------------------------------------------": "",
|
|
12
12
|
"dev": "quicksilver dev",
|
|
13
|
-
"dev:fresh": "
|
|
14
|
-
"dev:
|
|
15
|
-
"dev:
|
|
16
|
-
"dev:
|
|
17
|
-
"dev:
|
|
18
|
-
"dev:
|
|
13
|
+
"dev:fresh": "quicksilver dev --instance fresh",
|
|
14
|
+
"dev:ai": "quicksilver dev --instance ai",
|
|
15
|
+
"dev:ai2": "quicksilver dev --instance ai2",
|
|
16
|
+
"dev:h2": "quicksilver dev --instance h2",
|
|
17
|
+
"dev:postgresql": "quicksilver dev --instance postgresql",
|
|
18
|
+
"dev:mariadb": "quicksilver dev --instance mariadb",
|
|
19
|
+
"dev:mssql": "quicksilver dev --instance mssql",
|
|
20
|
+
"dev:oracle": "quicksilver dev --instance oracle",
|
|
19
21
|
"dev:debug": "quicksilver dev --debug",
|
|
20
|
-
"dev:api": "quicksilver
|
|
21
|
-
"dev:web": "
|
|
22
|
+
"dev:api": "quicksilver dev api",
|
|
23
|
+
"dev:web": "quicksilver dev web",
|
|
22
24
|
"// --- build subprojects -------------------------------------------": "",
|
|
23
25
|
"build": "pnpm build:api && pnpm build:web",
|
|
24
26
|
"build:api": "quicksilver gradle build",
|
|
@@ -25,13 +25,13 @@ catalogs:
|
|
|
25
25
|
client:
|
|
26
26
|
"@qs-charts/adapter-preact": "0.2.11"
|
|
27
27
|
"@qs-charts/core": "0.2.11"
|
|
28
|
-
"@qs-elements/web": "1.0.
|
|
29
|
-
"@qs-elements/web-preact": "1.0.
|
|
28
|
+
"@qs-elements/web": "1.0.165"
|
|
29
|
+
"@qs-elements/web-preact": "1.0.165"
|
|
30
30
|
quicksilver:
|
|
31
|
-
"@qs-platform/cli": "0.8.
|
|
32
|
-
"@qs-platform/preset-vite-web": "0.8.
|
|
33
|
-
"@qs-platform/web-module-core": "0.8.
|
|
34
|
-
"@qs-platform/web-module-org": "0.8.
|
|
31
|
+
"@qs-platform/cli": "0.8.29"
|
|
32
|
+
"@qs-platform/preset-vite-web": "0.8.29"
|
|
33
|
+
"@qs-platform/web-module-core": "0.8.29"
|
|
34
|
+
"@qs-platform/web-module-org": "0.8.29"
|
|
35
35
|
tooling:
|
|
36
36
|
"@types/node": "^26.4.0"
|
|
37
37
|
"sass": "^1.103.1"
|
|
@@ -19,3 +19,30 @@ packaging:
|
|
|
19
19
|
archive-name: {{PROJECT_CODE}}
|
|
20
20
|
fixed-modules: [{{PLATFORM_MODULE_CODES_QUOTED}}, '{{MODULE_CODE}}']
|
|
21
21
|
visible-modules:
|
|
22
|
+
|
|
23
|
+
# Development instances. `pnpm dev:<name>` runs `quicksilver dev --instance <name>`. The dev instance
|
|
24
|
+
# is required, `pnpm dev` starts it. port-offset gives the last two digits of the ports: web listens on
|
|
25
|
+
# the base port plus it, the API on that plus 2, and plus 1 and plus 3 are reserved. profile adds
|
|
26
|
+
# run/api/config/application-<profile>.yaml on top of application-dev.yaml. db-suffix is appended to
|
|
27
|
+
# the database name. rebuild: always rebuilds the database from init and demo data at every start. The
|
|
28
|
+
# developer manual (01-getting-started.md) describes every field, the Oracle user each instance logs in
|
|
29
|
+
# as, and the base ports to choose when several projects run on one machine.
|
|
30
|
+
dev:
|
|
31
|
+
# The main workspace listens on this plus the port offset: 6286 for dev.
|
|
32
|
+
main-base-port: 6200
|
|
33
|
+
# A git worktree with slot n listens on this plus n * 100 plus the port offset: 7186 for dev in
|
|
34
|
+
# worktree 1.
|
|
35
|
+
worktree-base-port: 7000
|
|
36
|
+
instances:
|
|
37
|
+
# 1x to 5x: one instance per database
|
|
38
|
+
h2: { port-offset: 10, profile: h2 }
|
|
39
|
+
postgresql: { port-offset: 20, profile: postgresql }
|
|
40
|
+
mariadb: { port-offset: 30, profile: mariadb }
|
|
41
|
+
mssql: { port-offset: 40, profile: mssql }
|
|
42
|
+
oracle: { port-offset: 50, profile: oracle }
|
|
43
|
+
# 8x: the developer
|
|
44
|
+
fresh: { port-offset: 80, db-suffix: fresh, rebuild: always }
|
|
45
|
+
dev: { port-offset: 86 }
|
|
46
|
+
# 9x: AI agents
|
|
47
|
+
ai: { port-offset: 92, db-suffix: ai }
|
|
48
|
+
ai2: { port-offset: 96, db-suffix: ai2 }
|
|
@@ -9,34 +9,75 @@ startup; nothing in this directory ships to your users.
|
|
|
9
9
|
|---|---|
|
|
10
10
|
| `application.yaml` | Base configuration: ports, CORS, cache, upload, Atomikos. **Declares no datasources** — those live in the profile files below |
|
|
11
11
|
| `application-dev.yaml` | The `dev` profile, active by default. Datasources for local development, plus `auto-init` (with `draft-sync` on) and `fail-on-unregistered-data-source` |
|
|
12
|
-
| `application-<dialect>.yaml` | One overlay per database dialect (`h2`, `postgresql`, `mariadb`, `mssql`, `oracle`)
|
|
12
|
+
| `application-<dialect>.yaml` | One overlay per database dialect (`h2`, `postgresql`, `mariadb`, `mssql`, `oracle`), each with its own datasources. `pnpm dev:<dialect>` starts the instance that uses it |
|
|
13
13
|
| `application-test.yaml` | Used by `modules/*/api` tests. In-memory H2, wiped on every run |
|
|
14
14
|
| `logback.xml` / `logback-test.xml` | Logging |
|
|
15
15
|
|
|
16
16
|
## Choosing a database
|
|
17
17
|
|
|
18
|
-
`pnpm dev` runs on a file-based H2 database with no setup. To use another dialect, run its script
|
|
19
|
-
|
|
20
|
-
`
|
|
18
|
+
`pnpm dev` runs on a file-based H2 database with no setup. To use another dialect, run its script,
|
|
19
|
+
such as `pnpm dev:postgresql` or `pnpm dev:mariadb`. Each script starts the development instance of
|
|
20
|
+
that name, `quicksilver dev --instance <dialect>`, which puts the dialect's profile on top of `dev`
|
|
21
|
+
and gives the instance ports and a database of its own. `pnpm qs dev --list` shows every instance.
|
|
21
22
|
|
|
22
|
-
The H2 profiles ship with working credentials (`sa` / `sa`)
|
|
23
|
+
The H2 profiles ship with working credentials (`sa` / `sa`): H2 creates the database file on first
|
|
23
24
|
connect, so there is nothing to change. In every other dialect file the user and `PASSWORD` are
|
|
24
25
|
placeholders you must replace.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
rule
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
The profile always comes from the instance. `quicksilver dev` refuses to start when
|
|
28
|
+
`SPRING_PROFILES_ACTIVE` is set, because a profile from elsewhere would not match the database the
|
|
29
|
+
instance is meant to use.
|
|
30
|
+
|
|
31
|
+
Each server-based dialect file names its database after this project, so several Quicksilver
|
|
32
|
+
products can share one database server without colliding: a project called `power-crm` gets
|
|
33
|
+
`power_crm_matrix`. When you point `application-dev.yaml` at a server, name that database
|
|
34
|
+
`power_crm_dev`, so that `pnpm dev` and the dialect instances never share one. Two files sit outside
|
|
35
|
+
that rule. Oracle's "database" is a PDB with a name fixed by the container image (`FREEPDB1`), so
|
|
36
|
+
`application-dev.yaml` and `application-oracle.yaml` are kept apart by user instead, see the next
|
|
37
|
+
section. The H2 profiles keep their databases as plain files under this project's own
|
|
38
|
+
`local/data/h2/` (`dev` for `pnpm dev`, `h2` for `pnpm dev:h2`) and so have nothing to collide with.
|
|
39
|
+
The datasource list is replaced as a whole, so when you change one entry, keep the other one listed
|
|
38
40
|
as well.
|
|
39
41
|
|
|
42
|
+
## Instances, worktrees and databases
|
|
43
|
+
|
|
44
|
+
Every workspace, the main checkout or a git worktree, runs its own instances side by side: `dev`,
|
|
45
|
+
`fresh`, `ai`, `ai2` and one per dialect. The instance decides the ports and the database. In the
|
|
46
|
+
main checkout `pnpm dev` uses web 6286 / API 6288 and the database configured here. A worktree gets
|
|
47
|
+
a slot number the first time an instance starts in it, and its ports move to 7n86 / 7n88 for slot n.
|
|
48
|
+
The base ports 6200 and 7000 are `main-base-port` and `worktree-base-port` in `quicksilver.yaml`.
|
|
49
|
+
|
|
50
|
+
The database name gets a suffix in a worktree (`worktree<slot>`) and for instances with a
|
|
51
|
+
`db-suffix` (`fresh`, `ai`, `ai2`), joined with underscores: `power_crm_dev_worktree1_ai`, or for H2
|
|
52
|
+
the file `dev_worktree1_ai`. In development mode a missing database is created at startup: the log
|
|
53
|
+
names it in a WARN line, and when the account may not create databases, startup fails with the
|
|
54
|
+
statement to run by hand. When a suffixed database is created next to an existing configured
|
|
55
|
+
database, MySQL, MariaDB and SQL Server copy its character set and collation. The first start of each
|
|
56
|
+
instance in a new worktree rebuilds its database from init and demo data, and so does every start of
|
|
57
|
+
`fresh`.
|
|
58
|
+
|
|
59
|
+
An Oracle database is a PDB and cannot be created per instance, so the suffix goes on the user
|
|
60
|
+
instead: the instance logs in as `<configured user>_<suffix>` with the configured URL and password,
|
|
61
|
+
for example `pnpm dev:oracle` in worktree 1 as `system_worktree1`. In Oracle a user is its own
|
|
62
|
+
schema, so each instance keeps its tables apart. In development mode a missing user is created at startup with the configured account:
|
|
63
|
+
the log names it in a WARN line. The account needs the DBA role, or the system privileges
|
|
64
|
+
`create profile`, `create user`, `drop user`, `grant any privilege` and `grant any role`. Without
|
|
65
|
+
them startup fails with every statement a DBA has to run. The configured user must be an unquoted
|
|
66
|
+
name that does not start with `C##`. Such a name belongs to a common user of the CDB, while the
|
|
67
|
+
derived user is a local user created in the PDB, and local user names cannot start with `C##`.
|
|
68
|
+
|
|
69
|
+
When you point `application-dev.yaml` at Oracle, give it a user other than the one in
|
|
70
|
+
`application-oracle.yaml`, for example `power_crm_dev` created for development. With the same user,
|
|
71
|
+
`pnpm dev` and `pnpm dev:oracle` share one schema in the main checkout, where rebuilding either with
|
|
72
|
+
`--fresh` wipes the data of the other. In a worktree they derive one user, and the second of the two
|
|
73
|
+
to start for the first time wipes the data of the other. No user is created when no suffix applies,
|
|
74
|
+
so create this one beforehand. Besides `create session`, `create table`, `create view`,
|
|
75
|
+
`select_catalog_role` and a tablespace quota, it needs the privileges above, which the instances
|
|
76
|
+
whose database name gets a suffix use to create their derived users.
|
|
77
|
+
|
|
78
|
+
To change the instance table, or the base ports when several projects run on one machine, see the
|
|
79
|
+
developer manual (`.quicksilver/manual`, "Getting started").
|
|
80
|
+
|
|
40
81
|
## H2 URLs
|
|
41
82
|
|
|
42
83
|
The two H2 parameters below are not optional. Both failures are quiet and show up far from the
|
|
@@ -52,9 +93,11 @@ configuration, so keep them when you edit an H2 URL:
|
|
|
52
93
|
## MySQL
|
|
53
94
|
|
|
54
95
|
MySQL works, but **you have to supply the driver**: Connector/J is GPLv2, so it is not bundled.
|
|
55
|
-
Add `runtimeOnly("com.mysql:mysql-connector-j")` to `run/api/build.gradle.kts`, then add
|
|
56
|
-
`application-mysql.yaml` overlay
|
|
57
|
-
|
|
96
|
+
Add `runtimeOnly("com.mysql:mysql-connector-j")` to `run/api/build.gradle.kts`, then add an
|
|
97
|
+
`application-mysql.yaml` overlay modelled on the other dialects, a `mysql` instance in the
|
|
98
|
+
`dev.instances` table of `quicksilver.yaml`, and a `dev:mysql` script running
|
|
99
|
+
`quicksilver dev --instance mysql`. Give the new instance a port offset at least 4 away from every
|
|
100
|
+
other one, for example 70. Every other dialect listed above ships with its driver.
|
|
58
101
|
|
|
59
102
|
## The dev database
|
|
60
103
|
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `dev` profile. Activated by default via `spring.profiles.active` in
|
|
3
|
-
# application.yaml, and by
|
|
3
|
+
# application.yaml, and by `quicksilver dev` for every instance.
|
|
4
4
|
#
|
|
5
5
|
spring:
|
|
6
6
|
application.name: DEV
|
|
7
7
|
|
|
8
8
|
quicksilver:
|
|
9
9
|
datasource:
|
|
10
|
+
# `quicksilver dev` gives every instance in every workspace a database of its own, derived from
|
|
11
|
+
# the URLs below. In a git worktree, and for instances with a db-suffix such as fresh and ai, it
|
|
12
|
+
# appends a suffix to the database name: dev_worktree1, dev_fresh, dev_ai. For H2 the suffix goes
|
|
13
|
+
# on the file name. A missing database is created at startup in development mode, also when you
|
|
14
|
+
# point dev at a server-based database here.
|
|
10
15
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
11
16
|
items:
|
|
12
17
|
- code: metadata
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `h2` profile: only the keys that differ from application-dev.yaml,
|
|
3
|
-
# everything else is inherited key by key.
|
|
4
|
-
#
|
|
3
|
+
# everything else is inherited key by key. `pnpm dev:h2` starts the `h2` instance with
|
|
4
|
+
# it. The log and Atomikos directories are passed by `quicksilver dev` for each instance.
|
|
5
5
|
#
|
|
6
|
-
logging:
|
|
7
|
-
file.path: local/log/application/h2
|
|
8
|
-
|
|
9
6
|
quicksilver:
|
|
10
7
|
datasource:
|
|
11
8
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
@@ -18,5 +15,3 @@ quicksilver:
|
|
|
18
15
|
url: "jdbc:h2:./local/data/h2/h2;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
|
|
19
16
|
user: sa
|
|
20
17
|
password: "sa"
|
|
21
|
-
atomikos:
|
|
22
|
-
log_base_dir: local/log/atomikos/h2
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `mariadb` profile: only the keys that differ from application-dev.yaml,
|
|
3
|
-
# everything else is inherited key by key.
|
|
4
|
-
#
|
|
3
|
+
# everything else is inherited key by key. `pnpm dev:mariadb` starts the `mariadb` instance with
|
|
4
|
+
# it. The log and Atomikos directories are passed by `quicksilver dev` for each instance.
|
|
5
5
|
#
|
|
6
|
-
logging:
|
|
7
|
-
file.path: local/log/application/mariadb
|
|
8
|
-
|
|
9
6
|
quicksilver:
|
|
10
7
|
datasource:
|
|
11
8
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
12
9
|
items:
|
|
13
10
|
- code: metadata
|
|
14
|
-
url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}
|
|
11
|
+
url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}_matrix?characterEncoding=utf8mb4"
|
|
15
12
|
user: root
|
|
16
13
|
password: "PASSWORD"
|
|
17
14
|
- code: business
|
|
18
|
-
url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}
|
|
15
|
+
url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}_matrix?characterEncoding=utf8mb4"
|
|
19
16
|
user: root
|
|
20
17
|
password: "PASSWORD"
|
|
21
|
-
atomikos:
|
|
22
|
-
log_base_dir: local/log/atomikos/mariadb
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `mssql` profile: only the keys that differ from application-dev.yaml,
|
|
3
|
-
# everything else is inherited key by key.
|
|
4
|
-
#
|
|
3
|
+
# everything else is inherited key by key. `pnpm dev:mssql` starts the `mssql` instance with
|
|
4
|
+
# it. The log and Atomikos directories are passed by `quicksilver dev` for each instance.
|
|
5
5
|
#
|
|
6
|
-
logging:
|
|
7
|
-
file.path: local/log/application/mssql
|
|
8
|
-
|
|
9
6
|
quicksilver:
|
|
10
7
|
datasource:
|
|
11
8
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
12
9
|
items:
|
|
13
10
|
- code: metadata
|
|
14
|
-
url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}
|
|
11
|
+
url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}_matrix;trustServerCertificate=true"
|
|
15
12
|
user: sa
|
|
16
13
|
password: "PASSWORD"
|
|
17
14
|
- code: business
|
|
18
|
-
url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}
|
|
15
|
+
url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}_matrix;trustServerCertificate=true"
|
|
19
16
|
user: sa
|
|
20
17
|
password: "PASSWORD"
|
|
21
|
-
atomikos:
|
|
22
|
-
log_base_dir: local/log/atomikos/mssql
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `oracle` profile: only the keys that differ from application-dev.yaml,
|
|
3
|
-
# everything else is inherited key by key.
|
|
4
|
-
#
|
|
3
|
+
# everything else is inherited key by key. `pnpm dev:oracle` starts the `oracle` instance with
|
|
4
|
+
# it. The log and Atomikos directories are passed by `quicksilver dev` for each instance.
|
|
5
5
|
#
|
|
6
|
-
logging:
|
|
7
|
-
file.path: local/log/application/oracle
|
|
8
|
-
|
|
9
6
|
quicksilver:
|
|
10
7
|
datasource:
|
|
11
8
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
@@ -18,5 +15,3 @@ quicksilver:
|
|
|
18
15
|
url: "jdbc:oracle:thin:@//localhost:1521/FREEPDB1"
|
|
19
16
|
user: system
|
|
20
17
|
password: "PASSWORD"
|
|
21
|
-
atomikos:
|
|
22
|
-
log_base_dir: local/log/atomikos/oracle
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Overlay for the `postgresql` profile: only the keys that differ from application-dev.yaml,
|
|
3
|
-
# everything else is inherited key by key.
|
|
4
|
-
#
|
|
3
|
+
# everything else is inherited key by key. `pnpm dev:postgresql` starts the `postgresql` instance with
|
|
4
|
+
# it. The log and Atomikos directories are passed by `quicksilver dev` for each instance.
|
|
5
5
|
#
|
|
6
|
-
logging:
|
|
7
|
-
file.path: local/log/application/postgresql
|
|
8
|
-
|
|
9
6
|
quicksilver:
|
|
10
7
|
datasource:
|
|
11
8
|
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
12
9
|
items:
|
|
13
10
|
- code: metadata
|
|
14
|
-
url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}
|
|
11
|
+
url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}_matrix?stringtype=unspecified"
|
|
15
12
|
user: postgres
|
|
16
13
|
password: "PASSWORD"
|
|
17
14
|
- code: business
|
|
18
|
-
url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}
|
|
15
|
+
url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}_matrix?stringtype=unspecified"
|
|
19
16
|
user: postgres
|
|
20
17
|
password: "PASSWORD"
|
|
21
|
-
atomikos:
|
|
22
|
-
log_base_dir: local/log/atomikos/postgresql
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Overlay for the `fresh` profile used by `pnpm dev:fresh`: only the keys that differ from
|
|
3
|
-
# application-dev.yaml, everything else is inherited key by key. It has a database of its own, which
|
|
4
|
-
# the script drops and rebuilds from init and demo data at every start, so the `pnpm dev` database
|
|
5
|
-
# is never touched.
|
|
6
|
-
#
|
|
7
|
-
logging:
|
|
8
|
-
file.path: local/log/application/fresh
|
|
9
|
-
|
|
10
|
-
quicksilver:
|
|
11
|
-
datasource:
|
|
12
|
-
# Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
|
|
13
|
-
items:
|
|
14
|
-
- code: metadata
|
|
15
|
-
url: "jdbc:h2:./local/data/h2/fresh;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
|
|
16
|
-
user: sa
|
|
17
|
-
password: "sa"
|
|
18
|
-
- code: business
|
|
19
|
-
url: "jdbc:h2:./local/data/h2/fresh;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
|
|
20
|
-
user: sa
|
|
21
|
-
password: "sa"
|
|
22
|
-
atomikos:
|
|
23
|
-
log_base_dir: local/log/atomikos/fresh
|