create-qs 0.0.0 → 0.8.23
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 +140 -2
- package/index.js +1884 -0
- package/package.json +31 -5
- package/template/default/.quicksilver/.gitattributes +4 -0
- package/template/default/.quicksilver/manual/en-US/00-setup.md +199 -0
- package/template/default/.quicksilver/manual/zh-CN/00-setup.md +199 -0
- package/template/default/.quicksilver/manual/zh-TW/00-setup.md +199 -0
- package/template/default/AGENTS.md +333 -0
- package/template/default/README.md +5 -0
- package/template/default/_gitignore +70 -0
- package/template/default/build.gradle.kts +5 -0
- package/template/default/eslint.config.js +137 -0
- package/template/default/gradle/repo.settings.gradle.kts +90 -0
- package/template/default/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template/default/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/template/default/gradle.properties +15 -0
- package/template/default/gradlew +248 -0
- package/template/default/gradlew.bat +93 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/build.gradle.kts +8 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/demo/README.md +11 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/init/rows/menus.jsons +1 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/init/rows/misc.jsons +15 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/upgrade/draft.jsons +1 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/kotlin/{{API_PACKAGE}}/AutoConfiguration.kt +25 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/SmokeTests.kt +61 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/TestConfiguration.kt +6 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/module.yaml +8 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/package.json +25 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/module.ts +16 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/vite-env.d.ts +10 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.app.json +7 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.json +7 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.node.json +7 -0
- package/template/default/modules/{{MODULE_DIRECTORY}}/web/vite.config.ts +11 -0
- package/template/default/package.json +76 -0
- package/template/default/pnpm-workspace.yaml +40 -0
- package/template/default/publishing.yaml +52 -0
- package/template/default/quicksilver.yaml +13 -0
- package/template/default/run/api/build.gradle.kts +8 -0
- package/template/default/run/api/config/README.md +76 -0
- package/template/default/run/api/config/application-dev.yaml +45 -0
- package/template/default/run/api/config/application-h2.yaml +22 -0
- package/template/default/run/api/config/application-mariadb.yaml +22 -0
- package/template/default/run/api/config/application-mssql.yaml +22 -0
- package/template/default/run/api/config/application-oracle.yaml +22 -0
- package/template/default/run/api/config/application-postgresql.yaml +22 -0
- package/template/default/run/api/config/application-test.yaml +28 -0
- package/template/default/run/api/config/application.yaml +84 -0
- package/template/default/run/api/config/logback-test.xml +141 -0
- package/template/default/run/api/config/logback.xml +142 -0
- package/template/default/run/web/index.html +14 -0
- package/template/default/run/web/index.ts +6 -0
- package/template/default/run/web/package.json +18 -0
- package/template/default/run/web/static/config.js +15 -0
- package/template/default/run/web/tsconfig.app.json +4 -0
- package/template/default/run/web/tsconfig.json +7 -0
- package/template/default/run/web/tsconfig.node.json +4 -0
- package/template/default/run/web/vite.config.ts +21 -0
- package/template/default/settings.gradle.kts +19 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# 00 環境準備
|
|
2
|
+
|
|
3
|
+
本章內容:**環境需求、基本設定、納入版本控制、啟動專案、目錄結構**
|
|
4
|
+
|
|
5
|
+
本章隨專案提交,手冊的其餘章節在 `pnpm install` 之後才會出現。本檔案由平台維護,再次安裝相依套件時會被覆寫,專案自身的說明請寫入 README。範例中的專案名稱 `power-crm` 與模組目錄 `sales` 僅用於說明目錄結構。
|
|
6
|
+
|
|
7
|
+
## 環境需求
|
|
8
|
+
|
|
9
|
+
| 名稱 | 版本 | 說明 |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| JDK | **25** | 後端 `sourceCompatibility` / `jvmTarget` 的版本(由平台的 Gradle 外掛程式設定),低於此版本會編譯失敗 |
|
|
12
|
+
| Node.js | **`>=22.13.0`** | pnpm 11 要求的最低版本 |
|
|
13
|
+
| pnpm | **11** | 必須使用 pnpm,不支援 npm 與 yarn。workspace、catalog、`allowBuilds` 均依賴 pnpm。
|
|
14
|
+
| Gradle | 無需安裝 | 專案內建 Gradle Wrapper(`./gradlew`),首次執行時自動下載 |
|
|
15
|
+
| 資料庫 | 無需安裝 | 預設使用檔案型 H2 資料庫。使用其他資料庫請參閱 [01 快速入門](01-getting-started.md#切換資料庫) |
|
|
16
|
+
|
|
17
|
+
## 基本設定
|
|
18
|
+
|
|
19
|
+
公開的 npmjs 上只發布了鷹架 `create-qs`,**因此無需任何設定即可建立專案**。平台的其餘部分,包括三組 npm 套件、Quicksilver 的 Gradle 外掛程式以及全部 Maven 構件(平台的 jar、基礎包與執行環境),均發布在內部 Nexus 上,執行 `pnpm install` 與首次執行 `./gradlew` 時都需要能夠存取它。
|
|
20
|
+
|
|
21
|
+
內部 Nexus 的位址不對外公開,因此新建立的專案不預設任何儲存庫位址。npm 與 Gradle 的儲存庫位址都設定在使用者目錄,每台電腦設定一次,對本機的所有專案生效。設定之前請先向提供 Quicksilver 的一方取得以下資訊,本章後文直接使用這些名稱。
|
|
22
|
+
|
|
23
|
+
| 名稱 | 說明 |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `NEXUS_MAVEN_URL` | 內部 Nexus 的 Maven 儲存庫位址,例如 `https://nexus-server/repository/maven-public/` |
|
|
26
|
+
| `NEXUS_NPM_URL` | 內部 Nexus 的 npm 儲存庫位址,例如 `https://nexus-server/repository/npm-public/` |
|
|
27
|
+
| `NEXUS_USER`、`NEXUS_PASSWORD` | Nexus 的帳號與密碼,僅在儲存庫需要身分驗證時使用 |
|
|
28
|
+
|
|
29
|
+
以下依設定檔逐一說明。兩個檔案均位於使用者目錄,對本機的所有專案生效,帳號與密碼只能設定在此處。需要由專案本身指定儲存庫位址時,請參閱文末的[不同專案使用不同儲存庫](#不同專案使用不同儲存庫)。
|
|
30
|
+
|
|
31
|
+
### `~/.npmrc`(使用者目錄)
|
|
32
|
+
|
|
33
|
+
npm 套件的儲存庫位址與憑證。`@qs-platform`、`@qs-elements`、`@qs-charts` 三個 scope 各占一行,其他相依套件仍從預設來源取得。
|
|
34
|
+
|
|
35
|
+
```ini
|
|
36
|
+
@qs-platform:registry=NEXUS_NPM_URL
|
|
37
|
+
@qs-elements:registry=NEXUS_NPM_URL
|
|
38
|
+
@qs-charts:registry=NEXUS_NPM_URL
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
以上三行對本機的所有 Quicksilver 專案生效,建立新專案時無需重複設定。單一專案需要使用其他儲存庫時,請參閱文末的[不同專案使用不同儲存庫](#不同專案使用不同儲存庫)。
|
|
42
|
+
|
|
43
|
+
儲存庫需要身分驗證時,權杖同樣儲存在此檔案中,無需手動編輯。執行以下指令並依提示輸入 `NEXUS_USER` 與 `NEXUS_PASSWORD`,npm 會將取得的權杖寫入該檔案。輸入密碼時不會顯示,也不會留在命令列歷史紀錄中。
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm login --registry=NEXUS_NPM_URL --auth-type=legacy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
寫入的內容類似 `//nexus-server/repository/npm-public/:_authToken=…`。
|
|
50
|
+
|
|
51
|
+
### `~/.gradle/gradle.properties`(使用者目錄)
|
|
52
|
+
|
|
53
|
+
Gradle 外掛程式與 Maven 構件的儲存庫位址及憑證統一設定在此檔案中。此檔案對本機所有專案生效,優先於專案根目錄 `gradle.properties` 中的同名設定項。新建立專案的 `gradle.properties` 中 `quicksilver.repo.url` 為空,此處也未設定時,建置會在啟動時回報錯誤並指向本章。外掛程式與構件的儲存庫宣告集中在專案的 `gradle/repo.settings.gradle.kts` 中,它只讀取這些設定項,請勿修改該檔案。
|
|
54
|
+
|
|
55
|
+
```properties
|
|
56
|
+
quicksilver.repo.url=NEXUS_MAVEN_URL
|
|
57
|
+
# 以下兩行僅在儲存庫需要身分驗證時加入
|
|
58
|
+
quicksilver.repo.user=NEXUS_USER
|
|
59
|
+
quicksilver.repo.password=NEXUS_PASSWORD
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
帳號與密碼須同時設定,只設定其中一項時,建置會在啟動時回報錯誤。兩項都不設定時以匿名方式存取。帳號與密碼只能寫在此檔案中,寫入專案根目錄的 `gradle.properties` 時建置同樣會回報錯誤,因為該檔案納入版本控制。需要身分驗證的儲存庫應使用 `https://` 位址,使用 `http://` 位址時,帳號與密碼會以明文傳輸。
|
|
63
|
+
|
|
64
|
+
同一組帳號也可用於發布。新建立專案的 `publishing.yaml` 中,發布目標的 `maven-credentials-prefix` 為 `quicksilver.repo`,發布時讀取的正是上面兩行,詳情請參閱 [08 打包與部署](08-packaging-deploy.md)。
|
|
65
|
+
|
|
66
|
+
不同專案需要使用不同儲存庫時,請參閱文末的[選用設定](#不同專案使用不同儲存庫)。
|
|
67
|
+
|
|
68
|
+
## 納入版本控制
|
|
69
|
+
|
|
70
|
+
透過 `create-qs` 建立的專案,建議儘早納入版本控制。clone 取得的專案已在版本控制中,可略過本節。在專案根目錄執行以下指令。
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git init
|
|
74
|
+
git add -A
|
|
75
|
+
git commit -m "Initial commit"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
專案範本已附帶 `.gitignore`。本手冊與 skill 由 `pnpm install` 寫入,除各語言的 `00-setup.md` 外均不納入版本控制,安裝相依套件後也不會出現在 `git status` 中。首次安裝相依套件會產生 `pnpm-lock.yaml`,它記錄相依套件的確切版本,應當納入版本控制。
|
|
79
|
+
|
|
80
|
+
## 啟動專案
|
|
81
|
+
|
|
82
|
+
在專案根目錄執行以下指令。
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pnpm i
|
|
86
|
+
pnpm dev
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
首次執行 `pnpm dev` 時需要下載 Gradle 與後端相依套件,並完成首次編譯,耗時較長。下載的內容快取在 `~/.gradle` 中,之後的啟動會快很多。
|
|
90
|
+
|
|
91
|
+
在瀏覽器中開啟 <http://localhost:6286>,使用 `admin` / `123456` 登入。
|
|
92
|
+
|
|
93
|
+
> 此帳號是 core 模組 init 資料檔中的**開發用種子資料**,重建開發資料庫後恢復為此密碼。**部署前必須修改。**
|
|
94
|
+
|
|
95
|
+
後端提供兩個健康檢查位址:
|
|
96
|
+
- <http://localhost:6288/api/metrics/status> 在服務開始接受請求後即回傳 UP
|
|
97
|
+
- <http://localhost:6288/api/metrics/ready> 在資料庫初始化完成之前回傳 503,**判斷服務是否可用應以它為準**。
|
|
98
|
+
|
|
99
|
+
## 目錄結構
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
power-crm/
|
|
103
|
+
├── AGENTS.md AI 程式設計助理的專案指示。Claude Code 需要 2.1.277 或更新版本才會讀取
|
|
104
|
+
├── README.md 專案說明
|
|
105
|
+
├── quicksilver.yaml 產品識別,包括標題、Kotlin 套件、Maven 座標、預留的命名空間、打包方式
|
|
106
|
+
├── publishing.yaml 發布目標與要發布的套件
|
|
107
|
+
├── package.json 專案指令碼(pnpm dev 等)與開發工具相依套件
|
|
108
|
+
├── pnpm-workspace.yaml pnpm 工作區與相依套件版本目錄
|
|
109
|
+
├── settings.gradle.kts Gradle 設定,指定平台版本並引入儲存庫宣告
|
|
110
|
+
├── build.gradle.kts Gradle 根建置指令碼,套用 Quicksilver 外掛程式
|
|
111
|
+
├── gradle.properties 平台版本,以及平台構件儲存庫的位址(新建立時為空)
|
|
112
|
+
├── gradlew, gradlew.bat Gradle Wrapper 啟動指令碼,設定位於 gradle/wrapper/
|
|
113
|
+
├── gradle/repo.settings.gradle.kts
|
|
114
|
+
│ 平台外掛程式與構件的儲存庫宣告,建立專案時寫入,請勿修改。升級時的處理請參閱 10 升級平台
|
|
115
|
+
├── eslint.config.js ESLint 設定
|
|
116
|
+
├── .gitignore 版本控制的忽略規則,決定哪些檔案不納入版本控制
|
|
117
|
+
├── modules/sales/ 業務模組,日常開發主要在此進行
|
|
118
|
+
│ ├── module.yaml 模組識別,包括 id、code、namespaces、相依、Web 套件名稱
|
|
119
|
+
│ ├── api/ 後端(Kotlin + Spring Boot)
|
|
120
|
+
│ │ └── data/init/ ← 初始化資料:tables.jsons(可選)、units/(每個單元一個檔案)與 rows/
|
|
121
|
+
│ └── web/ 前端(Preact + TypeScript)
|
|
122
|
+
│ └── src/module.ts 頁面、外掛、元件、樣式、圖示的註冊表
|
|
123
|
+
├── run/
|
|
124
|
+
│ ├── api/ Spring Boot 啟動專案
|
|
125
|
+
│ │ └── config/ 執行設定,每種資料庫對應一份 application-<資料庫>.yaml
|
|
126
|
+
│ └── web/ Vite 開發伺服器入口
|
|
127
|
+
├── test/e2e/scenarios/ 端對端測試案例,撰寫第一個案例時建立,請參閱 07 測試
|
|
128
|
+
├── local/ 本機的建置產物與設定覆寫(如 local/publishing.yaml),不納入版本控制
|
|
129
|
+
├── .quicksilver/
|
|
130
|
+
│ ├── .gitattributes 固定各語言 00-setup.md 的換行字元,納入版本控制
|
|
131
|
+
│ ├── manual/ 本手冊,依語言分目錄。僅各語言的 `00-setup.md`
|
|
132
|
+
│ │ 納入版本控制,其餘由 `pnpm install` 寫入
|
|
133
|
+
│ └── generated/ `pnpm qs sources` 取得的參考資料,不納入版本控制
|
|
134
|
+
├── .agents/skills/ 產品手冊與三個開發 skill,由 `pnpm install` 寫入,不納入版本控制
|
|
135
|
+
└── .claude/skills/ 指向上述各 skill 的符號連結,供 Claude Code 找到它們。
|
|
136
|
+
僅供 Claude Code 使用的 skill 可直接放在此目錄
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
手冊與 skill 由 `pnpm install` 從 `@qs-platform/cli` 寫入,隨 CLI 版本更新,每次整體覆寫,已納入版本控制的 `00-setup.md` 同樣會被覆寫。以 `qs-` 開頭的名稱歸平台所有,自訂的 skill 請使用其他前綴。上述目錄缺失時請執行 `pnpm qs docs`。使用 `--ignore-scripts` 安裝相依套件時不會寫入這些目錄,相依套件未變更時再次執行 `pnpm install` 也不會補回。
|
|
140
|
+
|
|
141
|
+
使用時請注意以下兩點:
|
|
142
|
+
|
|
143
|
+
- **`run/` 僅用於組裝各模組並啟動,不要在其中撰寫業務程式碼。** 此目錄通常無需修改。
|
|
144
|
+
- **應用程式行程的工作目錄是 `run/api`。** 設定中 `./local/...` 這類相對路徑都相對於 `run/api/`,而不是專案根目錄。路徑寫錯時的典型現象是資料庫為空,原因是應用程式在其他位置建立了新的資料庫。
|
|
145
|
+
|
|
146
|
+
## 下一步
|
|
147
|
+
|
|
148
|
+
安裝相依套件後,本目錄下會出現手冊的其餘章節。建議先閱讀[手冊目錄](README.md),再閱讀 [01 快速入門](01-getting-started.md),其中介紹建立專案時各選項的含義、常用指令以及如何切換資料庫。
|
|
149
|
+
|
|
150
|
+
首次使用時建議執行一次 `pnpm qs sources`,將平台的 API 文件、資料檔與前端 `.d.ts` 下載到 `.quicksilver/generated/`,手冊後續多處會引用其中的內容。
|
|
151
|
+
|
|
152
|
+
## 選用設定
|
|
153
|
+
|
|
154
|
+
### 不同專案使用不同儲存庫
|
|
155
|
+
|
|
156
|
+
基本設定中的兩個檔案均位於使用者目錄,對本機的所有專案生效。單一專案需要使用其他儲存庫,或者需要儲存庫位址隨專案一同分發、對 clone 此專案的所有人生效時,改為在專案中設定。**npm 與 Gradle 的優先順序相反**,兩者的設定方式因此不同。
|
|
157
|
+
|
|
158
|
+
npm 方面,專案根目錄 `pnpm-workspace.yaml` 中的 `registries` 優先於 `~/.npmrc`,在專案中加入此區段即可生效,`~/.npmrc` 中的三行無需刪除。新建立的專案不預設此區段。
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
registries:
|
|
162
|
+
'@qs-platform': NEXUS_NPM_URL
|
|
163
|
+
'@qs-elements': NEXUS_NPM_URL
|
|
164
|
+
'@qs-charts': NEXUS_NPM_URL
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Gradle 方面的優先順序與此相反,`~/.gradle/gradle.properties` 中的設定項會覆寫所有專案的同名設定項,因此需先從該檔案中刪除 `quicksilver.repo.url`,改為在各專案根目錄的 `gradle.properties` 中填寫這個新建立時為空的設定項。
|
|
168
|
+
|
|
169
|
+
各儲存庫使用不同的帳號時,再為每個專案指定憑證前綴。`quicksilver.repo.credentials` 指定前綴,帳號與密碼的鍵名為前綴加上 `.user` 與 `.password`,未設定時前綴為 `quicksilver.repo`。前綴的名稱可以自訂,以下範例使用 `acme.repo`。
|
|
170
|
+
|
|
171
|
+
```properties
|
|
172
|
+
# 專案根目錄的 gradle.properties
|
|
173
|
+
quicksilver.repo.url=NEXUS_MAVEN_URL
|
|
174
|
+
quicksilver.repo.credentials=acme.repo
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
在 `~/.gradle/gradle.properties` 中寫入該前綴對應的帳號與密碼。
|
|
178
|
+
|
|
179
|
+
```properties
|
|
180
|
+
acme.repo.user=NEXUS_USER
|
|
181
|
+
acme.repo.password=NEXUS_PASSWORD
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
專案固定到其他儲存庫卻未設定前綴時,建置會把使用者目錄中 `quicksilver.repo.user` 與 `quicksilver.repo.password` 這組帳號傳送給該儲存庫。因此固定到其他儲存庫時,應同時設定前綴。固定到允許匿名存取的儲存庫時,在專案根目錄的 `gradle.properties` 中寫一行留空的 `quicksilver.repo.credentials=`,建置將不傳送任何帳號。設定了前綴但缺少對應的帳號或密碼時,建置會在啟動時回報錯誤。
|
|
185
|
+
|
|
186
|
+
兩者的帳號與密碼均只能設定在使用者目錄的檔案中。`registries` 不接受憑證,專案根目錄的 `gradle.properties` 納入版本控制,其中只宜設定儲存庫位址與前綴,前綴本身不屬於機密資訊。
|
|
187
|
+
|
|
188
|
+
## 疑難排解
|
|
189
|
+
|
|
190
|
+
| 現象 | 可能的原因 |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `pnpm install` 重試約一分鐘後回報 `ERR_PNPM_META_FETCH_FAIL ... fetch failed` | 本機無法存取所設定的 npm 儲存庫位址,錯誤訊息中包含實際請求的位址 |
|
|
193
|
+
| `pnpm install` 在 `@qs-platform/*`(或 `@qs-elements/*`、`@qs-charts/*`)上回報 `ERR_PNPM_FETCH_404` | 所請求的儲存庫中沒有該套件。可能是該 scope 的儲存庫位址缺失或有誤,請求被送往公開的 npmjs(這三組套件只發布在內部 Nexus 上),也可能是位址指向了錯誤的儲存庫。位址有兩處來源,`pnpm-workspace.yaml` 的 `registries` 優先於 `~/.npmrc` 的 `@scope:registry`,兩處均有設定時需確認實際生效的是哪一處。部分儲存庫在缺少憑證時回傳 404 而不是 401 |
|
|
194
|
+
| `pnpm install` 回報 `ERR_PNPM_FETCH_401` | 儲存庫需要身分驗證,但 `~/.npmrc` 中沒有該位址的憑證,或憑證所對應的位址與實際生效的儲存庫位址不一致 |
|
|
195
|
+
| Gradle 啟動時回報 `quicksilver.repo.url is not set` | 使用者目錄與專案中都沒有設定 Maven 儲存庫位址,請依[基本設定](#基本設定)設定 |
|
|
196
|
+
| Gradle 啟動時回報 `Half a login is set` | 帳號與密碼只設定了其中一項,請補上錯誤訊息中列出的設定項 |
|
|
197
|
+
| Gradle 啟動時回報 `must not be in this project's gradle.properties` | 帳號或密碼寫入了專案根目錄的 `gradle.properties`,請將其移到錯誤訊息所指的使用者目錄檔案中 |
|
|
198
|
+
| Gradle 無法取得 `com.qsrun.quicksilver.*` 構件或外掛程式 | 平台構件只發布在內部 Nexus 上,Maven Central 中沒有。請檢查 `~/.gradle/gradle.properties` 中的 `quicksilver.repo.url`(外掛程式與構件均讀取此項)。此檔案未設定時,讀取專案根目錄 `gradle.properties` 中的同名設定項 |
|
|
199
|
+
| Gradle 回報 `Plugin [id: 'com.qsrun.quicksilver.gradle.root', ...] was not found` | 無法存取儲存庫,或儲存庫需要身分驗證。此錯誤不會提示 401,加上 `--info` 重新執行可看到 `HTTP 401`。需要身分驗證時,請依上文設定 `quicksilver.repo.user` 與 `quicksilver.repo.password` |
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file is the instruction set for AI coding assistants working on {{PROJECT_CODE}}. Claude Code
|
|
4
|
+
(2.1.277 or later) loads it automatically, as do the other tools that follow the AGENTS.md
|
|
5
|
+
convention. Do not add a `CLAUDE.md` next to it: when both exist, Claude Code reads only `CLAUDE.md`.
|
|
6
|
+
Other AI tools: treat this file as the entry point and follow the paths below to the handbook and
|
|
7
|
+
the skills.
|
|
8
|
+
|
|
9
|
+
## There is also a manual for people
|
|
10
|
+
|
|
11
|
+
[.quicksilver/manual/zh-CN/](.quicksilver/manual/zh-CN/README.md) is the developer manual — the same
|
|
12
|
+
product, explained in the order a person learns it, with the judgement calls spelled out ("does this
|
|
13
|
+
need code at all?"). It lives under `.quicksilver/manual/<language>/`: zh-CN is the source, and any
|
|
14
|
+
other language directory is a translation of it. You do not need to read it to work here, but when a
|
|
15
|
+
human asks *why* something is shaped the way it is, that is where the answer is written down, and it
|
|
16
|
+
is the right thing to point them at.
|
|
17
|
+
|
|
18
|
+
## Where dependencies come from
|
|
19
|
+
|
|
20
|
+
Quicksilver is not on the public registries. Its npm packages, Gradle plugin and Maven artifacts come
|
|
21
|
+
from a Nexus whose address is configured on each machine or in the project. New projects ship no
|
|
22
|
+
address. The handbook, the skills and the manual are all written
|
|
23
|
+
by `pnpm install`, so when `pnpm install` fails on a platform package they are not there yet. The one
|
|
24
|
+
exception is each language's `00-setup.md` in the manual: it is committed with the project, so it is
|
|
25
|
+
there before the first install.
|
|
26
|
+
**[.quicksilver/manual/en-US/00-setup.md](.quicksilver/manual/en-US/00-setup.md) is the guide** for npm
|
|
27
|
+
and Gradle alike: where each address lives, how to add a login, and which error means what.
|
|
28
|
+
|
|
29
|
+
Rules for you:
|
|
30
|
+
|
|
31
|
+
- The npm addresses live in `~/.npmrc` (`@qs-platform:registry` and the other two scopes), one
|
|
32
|
+
machine at a time. A `registries` section in `pnpm-workspace.yaml` overrides them for one project.
|
|
33
|
+
The Gradle address is `quicksilver.repo.url`, set in `~/.gradle/gradle.properties` for one machine
|
|
34
|
+
or in the project's `gradle.properties` for everyone on the project. The machine's file takes
|
|
35
|
+
precedence. The project ships the key empty. Editing the project files moves everyone on the
|
|
36
|
+
project, so when only this machine cannot reach the repository, ask the user which one they want.
|
|
37
|
+
Never edit `gradle/repo.settings.gradle.kts`, which declares the repositories for both the plugin
|
|
38
|
+
and the artifacts: it only reads those keys.
|
|
39
|
+
- **Never write a user name, password or token into a project file, and do not ask for one in the
|
|
40
|
+
conversation.** They belong in `~/.npmrc` and `~/.gradle/gradle.properties`, which the user edits.
|
|
41
|
+
Tell the user the exact lines to add, with placeholders. The Gradle login is
|
|
42
|
+
`quicksilver.repo.user` and `quicksilver.repo.password` in `~/.gradle/gradle.properties`. The build
|
|
43
|
+
stops if the login appears in the project's `gradle.properties`. `quicksilver.repo.credentials=<prefix>`
|
|
44
|
+
only names another place for that login, for projects on one machine that use different accounts,
|
|
45
|
+
so it may go in the project.
|
|
46
|
+
- Read the error before you touch an address. A 401 means the login is missing or does not match
|
|
47
|
+
the address. A 404 can mean a wrong address, or on some repositories a missing login.
|
|
48
|
+
|
|
49
|
+
## Read the handbook first
|
|
50
|
+
|
|
51
|
+
**Before touching any code, read [.agents/skills/qs-handbook/SKILL.md](.agents/skills/qs-handbook/SKILL.md).**
|
|
52
|
+
It is the Quicksilver product handbook: architecture overview, concept glossary, four convention
|
|
53
|
+
documents (backend / frontend / data / testing), the coding style, and a dozen topic guides. This
|
|
54
|
+
file repeats none of those rules — the rules live in the handbook and nowhere else. If
|
|
55
|
+
`.agents/skills/` is missing, run `pnpm qs docs` to write it (on a fresh clone, `pnpm install` first).
|
|
56
|
+
Do not expect another `pnpm install` to bring it back: with nothing new to install, pnpm skips the step
|
|
57
|
+
that writes it.
|
|
58
|
+
|
|
59
|
+
What lives here instead is how to *work* in this project: which server to start, where to look
|
|
60
|
+
things up, how far to widen a fix, and when to stop.
|
|
61
|
+
|
|
62
|
+
## Project layout
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
{{PROJECT_CODE}}/
|
|
66
|
+
├── AGENTS.md This file
|
|
67
|
+
├── quicksilver.yaml Product identity, Kotlin package, packaging
|
|
68
|
+
├── modules/{{MODULE_DIRECTORY}}/ Business module, backend and frontend side by side
|
|
69
|
+
│ ├── api/ Backend (Kotlin / Spring Boot)
|
|
70
|
+
│ ├── web/ Frontend (Preact / TypeScript)
|
|
71
|
+
│ └── module.yaml Module descriptor
|
|
72
|
+
├── run/
|
|
73
|
+
│ ├── api/ Spring Boot entry point; configuration under config/
|
|
74
|
+
│ └── web/ Vite dev server entry point
|
|
75
|
+
├── test/e2e/scenarios/ Your Playwright specs, run by `pnpm qs test verify`. Created with the first spec
|
|
76
|
+
├── local/ Machine-local files and overrides (such as local/publishing.yaml); never committed
|
|
77
|
+
├── .quicksilver/ Quicksilver's own material, not yours
|
|
78
|
+
│ ├── manual/ The developer manual for people, one directory per language. Only each
|
|
79
|
+
│ │ language's 00-setup.md is committed
|
|
80
|
+
│ └── generated/ What `pnpm qs sources` fetches; never committed, always re-fetchable
|
|
81
|
+
├── .agents/skills/ Handbook and three skills (below), from `pnpm install`, never committed
|
|
82
|
+
└── .claude/skills/ One symlink per skill into the above, so Claude Code finds them. Put a
|
|
83
|
+
Claude-only skill here under a name that does not start with qs-
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The manual and every `qs-*` skill come from `@qs-platform/cli`: whenever `pnpm install` installs
|
|
87
|
+
something, it rewrites them from the CLI version the project depends on, replacing whatever was there.
|
|
88
|
+
That includes the committed `00-setup.md` files, so do not edit them: project notes belong in `README.md`.
|
|
89
|
+
Anything named `qs-*` under `.agents/skills/` and `.claude/skills/` belongs to the platform, so give a
|
|
90
|
+
skill of your own another prefix. When they are missing (installed with `--ignore-scripts`, or
|
|
91
|
+
deleted), run `pnpm qs docs`.
|
|
92
|
+
|
|
93
|
+
Apart from each language's 00-setup.md, none of this is committed, so search tools that honour
|
|
94
|
+
`.gitignore` skip it, even when you point them at the directory. That covers ripgrep, most editors and
|
|
95
|
+
most AI search tools. To search the handbook or the manual, use
|
|
96
|
+
`grep -rn <pattern> .agents/skills .quicksilver/manual`, or `rg --no-ignore --hidden`.
|
|
97
|
+
|
|
98
|
+
Business code goes into the module under `modules/`. `run/` only wires the modules together so they
|
|
99
|
+
can be started; you rarely touch it.
|
|
100
|
+
|
|
101
|
+
## Common commands
|
|
102
|
+
|
|
103
|
+
Project scripts (see `scripts` in `package.json`; the database dialect scripts live there too):
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pnpm dev # Full dev environment (API + web), ports 6286 / 6288
|
|
107
|
+
pnpm dev:h2 # A second, isolated instance (own database and Atomikos directory)
|
|
108
|
+
pnpm build # Full build (backend + frontend)
|
|
109
|
+
pnpm test:api # Backend tests
|
|
110
|
+
pnpm lint # ESLint (pnpm lint:fix to autofix)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`qs` (long name `quicksilver`) is Quicksilver's own CLI. **You do not have to guess what it can do.**
|
|
114
|
+
The table lists every command of the CLI version this project was created with. This file is yours and
|
|
115
|
+
is not rewritten when the CLI is upgraded, so after an upgrade trust `pnpm qs --help`, and the command
|
|
116
|
+
index in the handbook's `references/architecture.md`, which every install refreshes:
|
|
117
|
+
|
|
118
|
+
| Command | When to reach for it |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `pnpm qs dev [services]` | You want only some of the services (api / web / app) rather than the full set |
|
|
121
|
+
| `pnpm qs gradle <tasks...>` | Run Gradle tasks; unrecognized options are passed straight through to Gradle |
|
|
122
|
+
| `pnpm qs new uuid [n]` | You need a new id for a jsons row — **mint one, never copy one from elsewhere** (a duplicated id fails far away from where it was introduced) |
|
|
123
|
+
| `pnpm qs new unit [code]` | Add a business unit: creates the unit file `data/init/units/<code>.jsons` holding the `$add: 'ac.unit'` block with freshly minted ids for the fields, the list, the form and the five standard pages; an entity unit also declares its four CRUD permissions there. `--owner account` adds row-level grants on the default account role to `data/init/rows/roles.jsons` and a Service that stamps the owner column. `--menu '日常/基础功能'` appends a row to `data/init/rows/menus.jsons` that hangs the list page under that menu; the row alone does not make the menu **visible** — some role still has to hold the unit's read permission. The same content is appended to the module's draft `data/upgrade/draft.jsons`, so installed environments get the unit too. Run it with no arguments to be asked for all of the above (tree, ownership, Kotlin layers, menu) and get the equivalent command line back |
|
|
124
|
+
| `pnpm qs data freeze` | Rename every module draft `data/upgrade/draft.jsons` with changes to the next upgrade file of the product version, `data/upgrade/<product version>/<version>.jsons`, and start a new draft. Write each data change into init and into the draft at the same time. Drafts are for development only: run this on the main branch before deploying to an environment that is kept, long-lived test environments included, then build the package again. A package built while a draft has changes is a draft package, for throwaway environments only. Later changes go into the draft again: changes to an upgrade file do not reach environments that have already run it |
|
|
125
|
+
| `pnpm qs build-vendor` | You changed a vendor dependency and need it rebundled into the single-file ESM used by the import map |
|
|
126
|
+
| `pnpm qs i18n extract` | You changed Chinese copy inside a jsons file and need each module's `i18n.tsv` refreshed |
|
|
127
|
+
| `pnpm qs sources` | **You need to see how Quicksilver itself does something** — drops the API docs, sources or decompiled classes, and every module's data files (`init/`, `demo/`, `upgrade/`), into `.quicksilver/generated/` (see below) |
|
|
128
|
+
| `pnpm qs docs` | Refresh `.agents/skills/qs-*` and `.quicksilver/manual/` from the installed CLI version. `pnpm install` runs it whenever it installs something, so you only need it when those directories are missing |
|
|
129
|
+
| `pnpm qs upgrade <version>` | Upgrade the platform: sets `quicksilver.version` in gradle.properties, `catalogs.quicksilver` and every other managed version to what that version's create-qs would write, then refreshes skills and the manual. Hand edits to managed values are set back. See `.quicksilver/manual/zh-CN/10-upgrading.md` |
|
|
130
|
+
| `pnpm qs test list` | You want to know which integration test profiles exist |
|
|
131
|
+
| `pnpm qs test run <profile>` | Run a full pipeline: package → install → start → verify → clean up |
|
|
132
|
+
| `pnpm qs test verify` | Run Playwright against an environment that is already up, without touching it |
|
|
133
|
+
| `pnpm qs release` | Build, then publish Maven artifacts and npm packages to a target declared in `publishing.yaml` |
|
|
134
|
+
|
|
135
|
+
Always run it as `pnpm qs <command>`: that picks up the version this project depends on, whatever is
|
|
136
|
+
or is not installed globally. Any directory inside the project works. Every command first moves to the
|
|
137
|
+
project root (the nearest directory holding both `pnpm-workspace.yaml` and `package.json`) and runs
|
|
138
|
+
there, while path options are still read relative to the directory you typed the command in.
|
|
139
|
+
Commands the CLI prints itself (hints in error messages, `--help` examples, the equivalent command line
|
|
140
|
+
`pnpm qs new unit` gives back) start with a bare `qs`. Put `pnpm` in front when you run one.
|
|
141
|
+
|
|
142
|
+
**For options, prerequisites and side effects always run `pnpm qs <command> --help`** — that is the
|
|
143
|
+
first-hand description and it lives in the same file as the implementation. The table above only
|
|
144
|
+
answers "what exists, and when do I want it".
|
|
145
|
+
|
|
146
|
+
## Publishing
|
|
147
|
+
|
|
148
|
+
`publishing.yaml` at the repository root declares **where** artifacts go and **which** packages get
|
|
149
|
+
published. `pnpm release` builds and then pushes both halves — the Maven artifacts of every module
|
|
150
|
+
and the npm package of every module's `web/` — and prints one summary listing everything that went
|
|
151
|
+
out.
|
|
152
|
+
|
|
153
|
+
Two rules worth knowing before you touch it:
|
|
154
|
+
|
|
155
|
+
- **Credentials never go in that file.** The npm token belongs in `~/.npmrc` as
|
|
156
|
+
`//<host>/:_authToken=<token>`; the Maven account belongs in `~/.gradle/gradle.properties` as
|
|
157
|
+
`<maven-credentials-prefix>.user` and `.password`. `pnpm qs release` checks both **before** it builds
|
|
158
|
+
anything and tells you which key is missing. The template's target uses `quicksilver.repo`, the
|
|
159
|
+
same login that pulls the platform, so one account covers both.
|
|
160
|
+
- **An empty URL means "not configured yet", not "use a default".** The template ships the
|
|
161
|
+
`internal` target with both URLs blank; publishing fails with an error naming the field until you
|
|
162
|
+
fill them in. That is deliberate — a default would quietly push your artifacts somewhere else.
|
|
163
|
+
|
|
164
|
+
Target names are yours. `internal` is just what the template calls its one target; add more by
|
|
165
|
+
copying the block (`staging`, `public`, one per customer — whatever fits), then
|
|
166
|
+
`pnpm qs release --target=<name>`. Set `confirm: true` on any target you do not want to publish to by
|
|
167
|
+
accident, and leave `git-checks` on (the default) wherever a release should be blocked by a dirty
|
|
168
|
+
working tree.
|
|
169
|
+
|
|
170
|
+
`pnpm qs release --dry-run` builds, prints the exact commands it would run, and stops. Use it whenever
|
|
171
|
+
you are unsure what a target would actually do.
|
|
172
|
+
|
|
173
|
+
## Development servers and ports
|
|
174
|
+
|
|
175
|
+
**An AI agent starts `pnpm dev:h2`, never `pnpm dev`.**
|
|
176
|
+
|
|
177
|
+
`pnpm dev` (web 6286 / api 6288) belongs to the person you are working with. It may well be running
|
|
178
|
+
already, and it is backed by the H2 file database `run/api/local/data/h2/database1`, which keeps
|
|
179
|
+
their data between starts: with `auto-init.draft-sync: true`, every start runs the upgrade drafts that
|
|
180
|
+
changed since the last one. Starting or restarting it yourself interrupts them and runs your
|
|
181
|
+
half-finished drafts against their data, so taking it over does not just steal a port.
|
|
182
|
+
|
|
183
|
+
`pnpm dev:h2` (6210 / 6211) is the isolated instance: its own database (`database2`), its own log
|
|
184
|
+
directory and its own Atomikos directory, so it can run side by side with theirs. The other dialect
|
|
185
|
+
scripts (`dev:postgresql` 6220/6221, `dev:mariadb` 6230/6231, `dev:mssql` 6240/6241, `dev:oracle`
|
|
186
|
+
6250/6251) are equally isolated, but they need a real server: fill in the placeholders in
|
|
187
|
+
`run/api/config/application-<dialect>.yaml` first.
|
|
188
|
+
|
|
189
|
+
Two more rules:
|
|
190
|
+
|
|
191
|
+
- **Port already taken?** Do not prefix the pnpm script — `pnpm dev:h2` sets `PORT` and `API_PORT`
|
|
192
|
+
itself, and a command-prefix assignment inside the script wins over the one you exported. Call the
|
|
193
|
+
CLI directly instead: `PORT=9001 API_PORT=9002 SPRING_PROFILES_ACTIVE=dev,h2 pnpm qs dev`. Pick
|
|
194
|
+
something in 9000–9999; if it is still taken, Vite fails outright — pick another.
|
|
195
|
+
- **Stop the server you started.** Especially after Playwright: leaving it running holds the port
|
|
196
|
+
and the database file.
|
|
197
|
+
|
|
198
|
+
## Signing in locally
|
|
199
|
+
|
|
200
|
+
Once the dev environment is up and you want to look at the result, use the administrator account
|
|
201
|
+
that ships with Quicksilver:
|
|
202
|
+
|
|
203
|
+
| Username | Password |
|
|
204
|
+
|---|---|
|
|
205
|
+
| `admin` | `123456` |
|
|
206
|
+
|
|
207
|
+
It is a development account seeded by core's init data files, so it comes back to this password
|
|
208
|
+
whenever the development database is rebuilt. `pnpm qs test verify` signs in with it too, for the
|
|
209
|
+
platform's own specs and for yours under `test/e2e/scenarios/`, which start out signed in as `admin`
|
|
210
|
+
(override it with the `E2E_ADMIN_USER` / `E2E_ADMIN_PASSWORD` environment variables).
|
|
211
|
+
|
|
212
|
+
> **Change it before you deploy.** This is seed data for development, not a credential that belongs
|
|
213
|
+
> anywhere near production.
|
|
214
|
+
|
|
215
|
+
## Looking at the development data
|
|
216
|
+
|
|
217
|
+
The profile file is the source of truth for where the data actually lives. Read
|
|
218
|
+
`run/api/config/application-dev.yaml` (or `application-<dialect>.yaml` for whichever profile you
|
|
219
|
+
started) and take the datasource from there; note that paths in it are relative to `run/api`, which
|
|
220
|
+
is the working directory of the API process.
|
|
221
|
+
|
|
222
|
+
For the default H2 profiles that means a file — `run/api/local/data/h2/database1` for `pnpm dev`,
|
|
223
|
+
`database2` for `pnpm dev:h2` — which you can open with any H2 client. For the other dialects,
|
|
224
|
+
connect with your usual client using the host, port, user and password from that same file.
|
|
225
|
+
|
|
226
|
+
The development database is kept between starts. With `auto-init.draft-sync: true`, every start runs
|
|
227
|
+
each module draft `data/upgrade/draft.jsons` that changed since the last start, and data entered by hand
|
|
228
|
+
or through the UI stays. **Write every data change into the draft as well as into `data/init/`**: a
|
|
229
|
+
change made only in `data/init/` reaches neither this database nor installed environments, and the
|
|
230
|
+
startup log lists such files. The two do not always hold the same commands. A removal takes the rows
|
|
231
|
+
out of `data/init/` and writes `$delete`, `@drop_column` or `@drop_table` into the draft. A fix to
|
|
232
|
+
existing data, such as filling a new column, goes into the draft only. Changes to `data/demo/` stay
|
|
233
|
+
out of the draft, since demo data runs on fresh installs only. Imperative commands in a draft (`@sql`,
|
|
234
|
+
`$update`, `$delete` ...) run once per `$key`; to run a changed one again, give it a new `$key`.
|
|
235
|
+
`$place` is the exception: it runs again whenever its draft runs. To rebuild the database from the
|
|
236
|
+
data files under `data/init/` and `data/demo/`, set `drop-first: true` in a profile override for one
|
|
237
|
+
start, then set it back.
|
|
238
|
+
|
|
239
|
+
## Development skills
|
|
240
|
+
|
|
241
|
+
Beyond the handbook there are three skills organized by task — "here is what this job consists of,
|
|
242
|
+
and where to confirm each step":
|
|
243
|
+
|
|
244
|
+
| Skill | When to use it | Entry point |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| `qs-unit` | Adding or reworking a business unit: `$add: 'ac.unit'` table and field definitions, list / form metadata, the Kotlin model / dao / service / controller, role permissions and menus | [.agents/skills/qs-unit/SKILL.md](.agents/skills/qs-unit/SKILL.md) |
|
|
247
|
+
| `qs-page` | Adding or reworking a page: the page class, registration in `module.ts`, the `ac.page` rows, the backend `xxx.page` preparation endpoint, page plugins | [.agents/skills/qs-page/SKILL.md](.agents/skills/qs-page/SKILL.md) |
|
|
248
|
+
| `qs-jsons` | Writing or changing init data files / upgrade files: creating tables, defining units, inserting seed data, writing `ac.text` copy | [.agents/skills/qs-jsons/SKILL.md](.agents/skills/qs-jsons/SKILL.md) |
|
|
249
|
+
|
|
250
|
+
Each skill's `examples/` directory holds complete samples you can copy from. The conventions they
|
|
251
|
+
cite live in the handbook's `references/` (`qs-jsons` carries a `references/` of its own as well).
|
|
252
|
+
|
|
253
|
+
## Looking up Quicksilver's own implementation
|
|
254
|
+
|
|
255
|
+
The handbook and the skills regularly ask you to "go confirm what that base class / annotation / data
|
|
256
|
+
row actually looks like". Quicksilver's own source is not part of this project — fetch it locally:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
pnpm qs sources
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
It fills `.quicksilver/generated/` with three things: `api/` holds the backend API documentation, sources or
|
|
263
|
+
decompiled classes (including core's own init data files), `web/` holds the frontend packages' type
|
|
264
|
+
declarations and readable sources (including the property and event types of the `<q-*>` elements),
|
|
265
|
+
and `README.md` explains what each directory contains. `.quicksilver/generated/` is not under version
|
|
266
|
+
control, so you can delete and re-fetch it at any time.
|
|
267
|
+
|
|
268
|
+
## Dependency versions: some pins are deliberate
|
|
269
|
+
|
|
270
|
+
**Do not raise the Vite or TypeScript version on your own initiative.** The versions this project was
|
|
271
|
+
generated with match the platform's, and that is not an accident: from Vite 8 on, the toolchain no
|
|
272
|
+
longer down-levels stage-3 decorators, and every page and component class here is built on decorators
|
|
273
|
+
(`@Page`, `@Handler` and friends) whose transform comes from the Quicksilver Vite preset.
|
|
274
|
+
|
|
275
|
+
The failure mode is what makes this worth a rule: in the projects where we hit it, **the build
|
|
276
|
+
succeeded, the exit code was 0, and the bundle threw a syntax error the moment it was loaded**. If an
|
|
277
|
+
upgrade is genuinely needed, treat it as its own task with its own verification — not as a step on
|
|
278
|
+
the way to something else.
|
|
279
|
+
|
|
280
|
+
**After changing a dependency, run `pnpm install` before anything else.** Otherwise pnpm 11 notices
|
|
281
|
+
the change and installs inside the next command you run, postinstall included, and its log lands in
|
|
282
|
+
that command's output, ahead of the ids from `pnpm qs new uuid` for instance. Offline, the command
|
|
283
|
+
fails along with the install.
|
|
284
|
+
|
|
285
|
+
## Fixing a problem: look one level up first
|
|
286
|
+
|
|
287
|
+
**When you fix something, do not stare only at the defect — look one level up and ask whether the
|
|
288
|
+
code around it wants restructuring.** A patch makes the symptom go away, but if the symptom comes
|
|
289
|
+
from the structure, the next one surfaces right next to it. Patching the same spot over and over is
|
|
290
|
+
the signal that the structure is what needs to move.
|
|
291
|
+
|
|
292
|
+
- **First decide: patch, or structural problem?** If this one place is simply written wrong, fix it
|
|
293
|
+
where it stands. If the same class of mistake is available elsewhere too, or if fixing it means
|
|
294
|
+
routing around an awkward design, the problem is structural.
|
|
295
|
+
- **If it is cheap, just do it.** The test: the change is contained, it can be finished in one go,
|
|
296
|
+
tests cover it, and it does not blur what this commit is about. Anything in that bracket, fix it
|
|
297
|
+
together with the defect — no need to come back and ask.
|
|
298
|
+
- **If it is expensive, fix the defect and then name the structure in your summary.** Say which part
|
|
299
|
+
is wrong, what the better shape would be, roughly what it would touch, and why you did not do it
|
|
300
|
+
now. Leave the decision to a human — do not quietly start a large refactor inside a bug fix.
|
|
301
|
+
- **Boundary:** this is about *refactoring* (structural change with no new behaviour visible to
|
|
302
|
+
callers), not about adding features. During cleanup and review the next section takes precedence —
|
|
303
|
+
the scope is frozen there, so even a cheap improvement gets reported rather than folded in.
|
|
304
|
+
|
|
305
|
+
## Fixes and reviews: no spreading, always terminable
|
|
306
|
+
|
|
307
|
+
**During cleanup, a "fix" fixes the listed problems only — no new features, no new abstractions, no
|
|
308
|
+
new generalizations.** Review is an infinite game: any piece of code can be examined further, and the
|
|
309
|
+
number of findings measures the effort spent, not the quality of the code. What keeps the loop from
|
|
310
|
+
terminating is usually not that the same problems keep coming back, but that every round of fixes
|
|
311
|
+
creates new surface to review.
|
|
312
|
+
|
|
313
|
+
- **No new features in a fix commit.** Anything that needs new logic to fix gets reported and tracked
|
|
314
|
+
separately, not slipped into a cleanup commit. The test: does this change introduce behaviour a
|
|
315
|
+
caller can see? Then it is a feature, not a fix. (Tracking it separately is not the same as
|
|
316
|
+
splitting one change into commits that do not compile — every commit still builds and passes.)
|
|
317
|
+
- **Decisions not to fix belong in the code, not only in the conversation.** Write them into the
|
|
318
|
+
nearest KDoc: what the deviation is, which direction it goes (looser or stricter), and what it
|
|
319
|
+
would take to close it. **A deviation annotated that way is not to be reported again as a new
|
|
320
|
+
finding in later reviews** — review tools have no memory across rounds; the marker in the code is
|
|
321
|
+
the memory. The one exception is when the annotation's premise no longer holds (the code changed,
|
|
322
|
+
or it was wrong to begin with): then change the annotation rather than staying silent.
|
|
323
|
+
- **Verify empirically before reporting a finding.** If it can be confirmed by querying the database,
|
|
324
|
+
running the command or reading the real code, do that; mark anything you could not confirm as
|
|
325
|
+
unverified. Review tools produce findings with a complete-looking chain of evidence and a wrong
|
|
326
|
+
conclusion, and an unverified item entering the backlog costs more than a missed one.
|
|
327
|
+
- **A human decides when it is done — do not wait for the review to say "nothing left".** The default
|
|
328
|
+
bar: **zero problems reachable by one ordinary user action**; everything else becomes an issue and
|
|
329
|
+
does not block the merge. Once you are there, run the relevant test suites and stop; do not open
|
|
330
|
+
another round.
|
|
331
|
+
- **Do not keep adding features between reviews.** If you are wrapping up, freeze the scope; if you
|
|
332
|
+
are adding features, land the current batch first. Doing both at once means reviewing a moving
|
|
333
|
+
target, which by definition does not converge.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# {{PROJECT_CODE}}
|
|
2
|
+
|
|
3
|
+
This is a Quicksilver project created with `create-qs`.
|
|
4
|
+
|
|
5
|
+
The developer manual is in `.quicksilver/manual/`. If this project was just created or cloned, read [00-setup.md](.quicksilver/manual/en-US/00-setup.md) first. It is also available in [简体中文](.quicksilver/manual/zh-CN/00-setup.md) and [繁體中文](.quicksilver/manual/zh-TW/00-setup.md).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
**/node_modules/
|
|
2
|
+
/.gradle/
|
|
3
|
+
|
|
4
|
+
# Logs
|
|
5
|
+
**/logs/
|
|
6
|
+
*.log
|
|
7
|
+
npm-debug.log*
|
|
8
|
+
pnpm-debug.log*
|
|
9
|
+
|
|
10
|
+
# Editor directories and files
|
|
11
|
+
.vscode/*
|
|
12
|
+
!.vscode/settings.json
|
|
13
|
+
!.vscode/extensions.json
|
|
14
|
+
.idea
|
|
15
|
+
.DS_Store
|
|
16
|
+
*.suo
|
|
17
|
+
*.ntvs*
|
|
18
|
+
*.njsproj
|
|
19
|
+
*.sln
|
|
20
|
+
*.sw?
|
|
21
|
+
|
|
22
|
+
# Environment variables
|
|
23
|
+
.env
|
|
24
|
+
.env.local
|
|
25
|
+
.env.development.local
|
|
26
|
+
.env.test.local
|
|
27
|
+
.env.production.local
|
|
28
|
+
|
|
29
|
+
# Build artifacts
|
|
30
|
+
/build/
|
|
31
|
+
/modules/*/api/build/
|
|
32
|
+
/modules/*/web/dist/
|
|
33
|
+
/modules/*/app/dist/
|
|
34
|
+
/run/api/build/
|
|
35
|
+
/run/web/dist/
|
|
36
|
+
|
|
37
|
+
# Local files
|
|
38
|
+
/local/
|
|
39
|
+
/run/api/local/
|
|
40
|
+
# Written by `pnpm qs test verify` and `pnpm qs test unit-smoke --ui`: the saved login state, results
|
|
41
|
+
# and screenshots
|
|
42
|
+
/test/e2e/local/
|
|
43
|
+
# Quicksilver's own material. The developer manual (.quicksilver/manual/) and the qs-* skills are
|
|
44
|
+
# written by @qs-platform/cli on every `pnpm install`, overwriting what was there, and are not
|
|
45
|
+
# committed, except each language's 00-setup.md: it is needed before the first install succeeds.
|
|
46
|
+
# .quicksilver/generated/ is what `pnpm qs sources` fetches and can be rebuilt at any time.
|
|
47
|
+
/.quicksilver/manual/**
|
|
48
|
+
!/.quicksilver/manual/*/
|
|
49
|
+
!/.quicksilver/manual/*/00-setup.md
|
|
50
|
+
/.quicksilver/generated/
|
|
51
|
+
/.agents/skills/qs-*/
|
|
52
|
+
/.claude/skills/qs-*
|
|
53
|
+
**/config/cipher.key
|
|
54
|
+
# Note: run/api/config/application-dev.yaml IS committed (it carries the dev datasources),
|
|
55
|
+
# but by convention local edits to it are not — see run/api/config/README.md.
|
|
56
|
+
# For an override that never enters version control, point QUICKSILVER_CONFIG_LOCATION at a
|
|
57
|
+
# config directory of your own; it is appended to the tail of spring.config.location and
|
|
58
|
+
# therefore wins over every profile file.
|
|
59
|
+
|
|
60
|
+
# Auto-generated files
|
|
61
|
+
/modules/*/api/src/main/resources/QS-INF/module.json
|
|
62
|
+
|
|
63
|
+
# Kotlin tooling
|
|
64
|
+
/.kotlin/
|
|
65
|
+
|
|
66
|
+
# Test artifacts
|
|
67
|
+
**/coverage/
|
|
68
|
+
**/test-results/
|
|
69
|
+
**/playwright-report/
|
|
70
|
+
**/blob-report/
|